Ticket #2219: fscscy.c

File fscscy.c, 22.4 KB (added by jwrdegoede, 5 years ago)

New 2.6 kernel FSC Scylla driver

Line 
1/*
2 * fscscy.c - Part of lm_sensors, Linux kernel modules for hardware
3 * monitoring
4 * Copyright (C) 2007 Hans de Goede <j.w.r.degoede@hhs.nl>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21/*
22 *  New merged Fujitsu Siemens hwmon driver, supporting the Scylla, Poseidon,
23 *  Hermes and Heimdall chips
24 *
25 *  Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6
26 *  (candidate) fschmd drivers:
27 *  Copyright (C) 2006 Thilo Cestonaro <thilo.cestonaro.external@fujitsu-siemens.com>
28 *  Copyright (C) 2003, 2004 Reinhard Nissl <rnissl@gmx.de>
29 *  Copyright (C) 2000 Hermann Jung <hej@odn.de>
30 *  Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
31 *  and Philip Edelbrock <phil@netroedge.com>
32 */
33
34#include <linux/module.h>
35#include <linux/init.h>
36#include <linux/slab.h>
37#include <linux/jiffies.h>
38#include <linux/i2c.h>
39#include <linux/hwmon.h>
40#include <linux/hwmon-sysfs.h>
41#include <linux/err.h>
42#include <linux/mutex.h>
43#include <linux/sysfs.h>
44
45/* Addresses to scan */
46static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
47
48/* Insmod parameters */
49I2C_CLIENT_INSMOD_4(fscscy, fscpos, fscher, fschmd);
50
51/*
52 * The FSCSCY registers and other defines
53 */
54
55/* chip identification */
56#define FSCSCY_REG_IDENT_0              0x00
57#define FSCSCY_REG_IDENT_1              0x01
58#define FSCSCY_REG_IDENT_2              0x02
59#define FSCSCY_REG_REVISION             0x03
60
61/* global control and status */
62#define FSCSCY_REG_EVENT_STATE          0x04
63#define FSCSCY_REG_CONTROL              0x05
64
65/* watchdog (support to be implemented) */
66#define FSCSCY_REG_WDOG_PRESET          0x28
67#define FSCSCY_REG_WDOG_STATE           0x23
68#define FSCSCY_REG_WDOG_CONTROL         0x21
69
70/* voltage supervision */
71#define FSCSCY_REG_VOLT_12              0x45
72#define FSCSCY_REG_VOLT_5               0x42
73#define FSCSCY_REG_VOLT_BATT            0x48
74
75/* minimum pwm at which the fan is driven (pwm can by increased depending on
76   the temp. Notice that for the scy some fans share there minimum speed.
77   Also notice that with the scy the sensor order is different then with the
78   other chips, this order was in the 2.4 driver and kept for consistency. */
79static const u8 FSCSCY_REG_FAN_MIN[4][6] = {
80        { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 },         /* scy */
81        { 0x55, 0x65 },                                 /* pos */
82        { 0x55, 0x65, 0xb5 },                           /* her */
83        { 0x55, 0x65, 0xa5, 0xb5, 0xc5 } };             /* hmd */
84
85/* actual fan speed */ 
86static const u8 FSCSCY_REG_FAN_ACT[4][6] = {
87        { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb },         /* scy */
88        { 0x0e, 0x6b, 0xab },                           /* pos */
89        { 0x0e, 0x6b, 0xbb },                           /* her */
90        { 0x5b, 0x6b, 0xab, 0xbb, 0xcb } };             /* hmd */
91
92/* fan status registers */
93static const u8 FSCSCY_REG_FAN_STATE[4][6] = {
94        { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 },         /* scy */
95        { 0x0d, 0x62, 0xa2 },                           /* pos */
96        { 0x0d, 0x62, 0xb2 },                           /* her */
97        { 0x52, 0x62, 0xa2, 0xb2, 0xc2 } };             /* hmd */
98       
99/* fan ripple / divider registers */   
100static const u8 FSCSCY_REG_FAN_RIPPLE[4][6] = {
101        { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf },         /* scy */
102        { 0x0f, 0x6f, 0xaf },                           /* pos */
103        { 0x0f, 0x6f, 0xbf },                           /* her */
104        { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf } };             /* hmd */
105
106static const int FSCSCY_NO_FAN_SENSORS[4] = { 6, 3, 3, 5 };
107
108
109/* actual temperature registers */
110static const u8 FSCSCY_REG_TEMP_ACT[4][5] = {
111        { 0x64, 0xD0, 0x32, 0x35 },                     /* scy */
112        { 0x64, 0x32, 0x35 },                           /* pos */
113        { 0x64, 0x32, 0x35 },                           /* her */
114        { 0x70, 0x80, 0x90, 0xd0, 0xe0 } };             /* hmd */
115
116/* temperature state registers */
117static const u8 FSCSCY_REG_TEMP_STATE[4][5] = {
118        { 0x71, 0xd1, 0x81, 0x91 },                     /* scy */
119        { 0x71, 0x81, 0x91 },                           /* pos */
120        { 0x71, 0x81, 0x91 },                           /* her */
121        { 0x71, 0x81, 0x91, 0xd1, 0xe1 } };             /* hmd */
122
123/* temperature high limit registers, FSC does not document these. Proven to be
124   there with field testing on the fscher, already supported / used in the
125   fscscy 2.4 driver. FSC has confirmed that the fschmd has registers at these
126   addresses, but doesn't want to confirm they are the same as with the fscher?
127   For the fscpos these still needs to be tested / confirmed. */
128static const u8 FSCSCY_REG_TEMP_LIMIT[4][5] = {
129        { 0x76, 0xd6, 0x86, 0x96 },                     /* scy */
130        { 0x76, 0x86, 0x96 },                           /* pos */
131        { 0x76, 0x86, 0x96 },                           /* her */
132        { 0x76, 0x86, 0x96, 0xd6, 0xe6 } };             /* hmd */     
133
134/* These were found through experimenting with an fscher, currently they are
135   not used, but we keep them around for future reference.
136static const u8 FSCHER_REG_TEMP_AUTOP1[] =      { 0x73, 0x83, 0x93 };
137static const u8 FSCHER_REG_TEMP_AUTOP2[] =      { 0x75, 0x85, 0x95 }; */
138
139static const int FSCSCY_NO_TEMP_SENSORS[4] = { 4, 3, 3, 5 }; 
140
141#define FSCSCY_NAME "fscscy"
142
143/*
144 * Functions declarations
145 */
146
147static int fscscy_attach_adapter(struct i2c_adapter *adapter);
148static int fscscy_detach_client(struct i2c_client *client);
149static struct fscscy_data *fscscy_update_device(struct device *dev);
150
151/*
152 * Driver data (common to all clients)
153 */
154
155static struct i2c_driver fscscy_driver = {
156        .driver = {
157                .name   = FSCSCY_NAME,
158        },
159        .attach_adapter = fscscy_attach_adapter,
160        .detach_client  = fscscy_detach_client,
161};
162
163/*
164 * Client data (each client gets its own)
165 */
166
167struct fscscy_data {
168        enum chips kind;
169        struct i2c_client client;
170        struct class_device *class_dev;
171        struct mutex update_lock;
172        char valid; /* zero until following fields are valid */
173        unsigned long last_updated; /* in jiffies */
174
175        /* register values */
176        u8 global_control;      /* global control register */
177        u8 volt[3];             /* 12, 5, battery voltage */ 
178        u8 temp_act[5];         /* temperature */
179        u8 temp_status[5];      /* status of sensor */
180        u8 temp_max[6];         /* high temp limit, notice: undocumented! */
181        u8 fan_act[6];          /* fans revolutions per second */
182        u8 fan_status[6];       /* fan status */
183        u8 fan_min[6];          /* fan min value for rps */
184        u8 fan_ripple[6];       /* divider for rps */
185};
186
187/*
188 * Sysfs attr show / store functions
189 */
190
191static ssize_t show_in_value(struct device *dev,
192        struct device_attribute *devattr, char *buf)
193{
194        const int max_reading[3] = { 14200, 6600, 3300 };
195        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
196        struct fscscy_data *data = fscscy_update_device(dev);
197
198        return sprintf(buf, "%d\n", (data->volt[attr->index] *
199                max_reading[attr->index]) / 255);
200}
201
202
203#define TEMP_FROM_REG(val)      (((val) - 128) * 1000)
204
205static ssize_t show_temp_value(struct device *dev,
206        struct device_attribute *devattr, char *buf)
207{
208        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
209        struct fscscy_data *data = fscscy_update_device(dev);
210
211        return sprintf(buf, "%d\n",
212                TEMP_FROM_REG(data->temp_act[attr->index]));
213}
214
215static ssize_t show_temp_max(struct device *dev,
216        struct device_attribute *devattr, char *buf)
217{
218        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
219        struct fscscy_data *data = fscscy_update_device(dev);
220
221        return sprintf(buf, "%d\n", TEMP_FROM_REG(
222                data->temp_max[attr->index]));
223}
224
225static ssize_t store_temp_max(struct device *dev, struct device_attribute
226        *devattr, const char *buf, size_t count)
227{
228        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
229        struct fscscy_data *data = i2c_get_clientdata(to_i2c_client(dev));
230        long v = simple_strtol(buf, NULL, 10) / 1000;
231
232        SENSORS_LIMIT(v, -128, 127);
233        v += 128;
234
235        mutex_lock(&data->update_lock);
236        i2c_smbus_write_byte_data(&data->client,
237                FSCSCY_REG_TEMP_LIMIT[data->kind][attr->index], v);
238        data->temp_max[attr->index] = v;
239        mutex_unlock(&data->update_lock);
240
241        return count;
242}
243
244static ssize_t show_temp_fault(struct device *dev,
245        struct device_attribute *devattr, char *buf)
246{
247        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
248        struct fscscy_data *data = fscscy_update_device(dev);
249
250        /* bit 0 set means sensor working ok, so no fault! */
251        if (data->temp_status[attr->index] & 0x01)
252                return sprintf(buf, "0\n");
253        else
254                return sprintf(buf, "1\n");
255}
256
257static ssize_t show_temp_alarm(struct device *dev,
258        struct device_attribute *devattr, char *buf)
259{
260        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
261        struct fscscy_data *data = fscscy_update_device(dev);
262
263        /* only signal an alarm if the sensor is working and alert == 1 */
264        if ((data->temp_status[attr->index] & 0x03) == 0x03)
265                return sprintf(buf, "1\n");
266        else
267                return sprintf(buf, "0\n");
268}
269
270
271#define RPM_FROM_REG(val)       (val*60)
272
273static ssize_t show_fan_value(struct device *dev,
274        struct device_attribute *devattr, char *buf)
275{
276        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
277        struct fscscy_data *data = fscscy_update_device(dev);
278
279        return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[attr->index]));
280}
281
282static ssize_t show_fan_div(struct device *dev,
283        struct device_attribute *devattr, char *buf)
284{
285        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
286        struct fscscy_data *data = fscscy_update_device(dev);
287
288        /* bits 2..7 reserved => mask with 3 */ 
289        return sprintf(buf, "%d\n", 1 << (data->fan_ripple[attr->index] & 3));
290}
291
292static ssize_t store_fan_div(struct device *dev, struct device_attribute
293        *devattr, const char *buf, size_t count)
294{
295        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
296        struct fscscy_data *data = fscscy_update_device(dev);
297        /* supported values: 2, 4, 8 */
298        unsigned long v = simple_strtoul(buf, NULL, 10);
299
300        switch (v) {
301                case 2: v = 1; break;
302                case 4: v = 2; break;
303                case 8: v = 3; break;
304                default:
305                        dev_err(&data->client.dev, "fan_div value %lu not "
306                                 "supported. Choose one of 2, 4 or 8!\n", v);
307                        return -EINVAL;
308        }
309
310        mutex_lock(&data->update_lock);
311
312        /* bits 2..7 reserved => mask with 0x03 */
313        data->fan_ripple[attr->index] &= ~0x03;
314        data->fan_ripple[attr->index] |= v;
315
316        i2c_smbus_write_byte_data(&data->client,
317                FSCSCY_REG_FAN_RIPPLE[data->kind][attr->index],
318                data->fan_ripple[attr->index]);
319
320        mutex_unlock(&data->update_lock);
321
322        return count;
323}
324
325static ssize_t show_fan_alarm(struct device *dev,
326        struct device_attribute *devattr, char *buf)
327{
328        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
329        struct fscscy_data *data = fscscy_update_device(dev);
330
331        if (data->fan_status[attr->index] & 0x04)
332                return sprintf(buf, "1\n");
333        else
334                return sprintf(buf, "0\n");
335}
336
337
338static ssize_t show_pwm_auto_point1_pwm(struct device *dev,
339        struct device_attribute *devattr, char *buf)
340{
341        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
342        int val = fscscy_update_device(dev)->fan_min[attr->index];
343
344        /* 0 = allow turning off, 1-255 = 50-100% */
345        if (val)
346                val = val / 2 + 128;
347       
348        return sprintf(buf, "%d\n", val);
349}
350
351static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
352        struct device_attribute *devattr, const char *buf, size_t count)
353{
354        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
355        struct fscscy_data *data = i2c_get_clientdata(to_i2c_client(dev));
356        unsigned long v = simple_strtoul(buf, NULL, 10);
357       
358        /* register: 0 = allow turning off, 1-255 = 50-100% */
359        if (v) {
360                SENSORS_LIMIT(v, 128, 255);
361                v = (v - 128) * 2 + 1;
362        }
363
364        mutex_lock(&data->update_lock);
365
366        i2c_smbus_write_byte_data(&data->client,
367                FSCSCY_REG_FAN_MIN[data->kind][attr->index], v);
368        data->fan_min[attr->index] = v;
369
370        mutex_unlock(&data->update_lock);
371       
372        return count;
373}
374
375
376/* The FSC hwmon family has the ability to force an attached alert led to flash
377   from software, we export this as an alert_led sysfs attr */
378static ssize_t show_alert_led(struct device *dev,
379        struct device_attribute *devattr, char *buf)
380{
381        struct fscscy_data *data = fscscy_update_device(dev);
382
383        if (data->global_control & 0x01)
384                return sprintf(buf, "1\n");
385        else
386                return sprintf(buf, "0\n");
387}
388
389static ssize_t store_alert_led(struct device *dev,
390        struct device_attribute *devattr, const char *buf, size_t count)
391{
392        struct fscscy_data *data = fscscy_update_device(dev);
393        unsigned long v = simple_strtoul(buf, NULL, 10);
394
395        mutex_lock(&data->update_lock);
396       
397        if (v)
398                data->global_control |= 0x01;
399        else
400                data->global_control &= ~0x01;
401
402        i2c_smbus_write_byte_data(&data->client, FSCSCY_REG_CONTROL, v);
403        mutex_unlock(&data->update_lock);
404
405        return count;
406}
407
408static struct sensor_device_attribute fscscy_attr[] = {
409        SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0),
410        SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1),
411        SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2),
412        SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0),
413};
414
415static struct sensor_device_attribute fscscy_temp_attr[] = {
416        SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0),
417        SENSOR_ATTR(temp1_max,   0644, show_temp_max, store_temp_max, 0),
418        SENSOR_ATTR(temp1_fault, 0444, show_temp_fault, NULL, 0),
419        SENSOR_ATTR(temp1_alarm, 0444, show_temp_alarm, NULL, 0),
420        SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1),
421        SENSOR_ATTR(temp2_max,   0644, show_temp_max, store_temp_max, 1),
422        SENSOR_ATTR(temp2_fault, 0444, show_temp_fault, NULL, 1),
423        SENSOR_ATTR(temp2_alarm, 0444, show_temp_alarm, NULL, 1),
424        SENSOR_ATTR(temp3_input, 0444, show_temp_value, NULL, 2),
425        SENSOR_ATTR(temp3_max,   0644, show_temp_max, store_temp_max, 2),
426        SENSOR_ATTR(temp3_fault, 0444, show_temp_fault, NULL, 2),
427        SENSOR_ATTR(temp3_alarm, 0444, show_temp_alarm, NULL, 2),
428        SENSOR_ATTR(temp4_input, 0444, show_temp_value, NULL, 3),
429        SENSOR_ATTR(temp4_max,   0644, show_temp_max, store_temp_max, 3),
430        SENSOR_ATTR(temp4_fault, 0444, show_temp_fault, NULL, 3),
431        SENSOR_ATTR(temp4_alarm, 0444, show_temp_alarm, NULL, 3),
432        SENSOR_ATTR(temp5_input, 0444, show_temp_value, NULL, 4),
433        SENSOR_ATTR(temp5_max,   0644, show_temp_max, store_temp_max, 4),
434        SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4),
435        SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4),
436};
437
438static struct sensor_device_attribute fscscy_fan_attr[] = {
439        SENSOR_ATTR(fan1_input, 0444, show_fan_value, NULL, 0),
440        SENSOR_ATTR(fan1_div,   0644, show_fan_div, store_fan_div, 0),
441        SENSOR_ATTR(fan1_alarm, 0444, show_fan_alarm, NULL, 0),
442        SENSOR_ATTR(pwm1_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
443                store_pwm_auto_point1_pwm, 0),
444        SENSOR_ATTR(fan2_input, 0444, show_fan_value, NULL, 1),
445        SENSOR_ATTR(fan2_div,   0644, show_fan_div, store_fan_div, 1),
446        SENSOR_ATTR(fan2_alarm, 0444, show_fan_alarm, NULL, 1),
447        SENSOR_ATTR(pwm2_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
448                store_pwm_auto_point1_pwm, 1),
449        SENSOR_ATTR(fan3_input, 0444, show_fan_value, NULL, 2),
450        SENSOR_ATTR(fan3_div,   0644, show_fan_div, store_fan_div, 2),
451        SENSOR_ATTR(fan3_alarm, 0444, show_fan_alarm, NULL, 2),
452        SENSOR_ATTR(pwm3_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
453                store_pwm_auto_point1_pwm, 2),
454        SENSOR_ATTR(fan4_input, 0444, show_fan_value, NULL, 3),
455        SENSOR_ATTR(fan4_div,   0644, show_fan_div, store_fan_div, 3),
456        SENSOR_ATTR(fan4_alarm, 0444, show_fan_alarm, NULL, 3),
457        SENSOR_ATTR(pwm4_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
458                store_pwm_auto_point1_pwm, 3),
459        SENSOR_ATTR(fan5_input, 0444, show_fan_value, NULL, 4),
460        SENSOR_ATTR(fan5_div,   0644, show_fan_div, store_fan_div, 4),
461        SENSOR_ATTR(fan5_alarm, 0444, show_fan_alarm, NULL, 4),
462        SENSOR_ATTR(pwm5_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
463                store_pwm_auto_point1_pwm, 4),
464        SENSOR_ATTR(fan6_input, 0444, show_fan_value, NULL, 5),
465        SENSOR_ATTR(fan6_div,   0644, show_fan_div, store_fan_div, 5),
466        SENSOR_ATTR(fan6_alarm, 0444, show_fan_alarm, NULL, 5),
467        SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
468                store_pwm_auto_point1_pwm, 5),
469};
470
471
472/*
473 * Real code
474 */
475
476static int fscscy_detect(struct i2c_adapter *adapter, int address, int kind)
477{
478        struct i2c_client *new_client;
479        struct fscscy_data *data;
480        u8 revision;
481        const char *names[4] = { "Scylla", "Poseidon", "Hermes", "Heimdall" };
482        /* We cannot just use FSCSCY_NO_FAN_SENSORS * 4, because the fscpos
483           doesn't have a FAN_MIN register for its third (last) fan */
484        int fan_sysfs_attr = 0, i, err = 0;
485
486        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
487                return 0;
488
489        /* OK. For now, we presume we have a valid client. We now create the
490         * client structure, even though we cannot fill it completely yet.
491         * But it allows us to access i2c_smbus_read_byte_data. */
492        if (!(data = kzalloc(sizeof(struct fscscy_data), GFP_KERNEL)))
493                return -ENOMEM;
494
495        /* The common I2C client data is placed right before the
496         * Poseidon-specific data. */
497        new_client = &data->client;
498        i2c_set_clientdata(new_client, data);
499        new_client->addr = address;
500        new_client->adapter = adapter;
501        new_client->driver = &fscscy_driver;
502        new_client->flags = 0;
503        strlcpy(new_client->name, FSCSCY_NAME, I2C_NAME_SIZE);
504        data->valid = 0;
505        mutex_init(&data->update_lock);
506
507        /* Detect & Identify the chip */
508        if (kind <= 0) {
509                char id[4];
510               
511                id[0] = i2c_smbus_read_byte_data(new_client,
512                                FSCSCY_REG_IDENT_0);
513                id[1] = i2c_smbus_read_byte_data(new_client,
514                                FSCSCY_REG_IDENT_1);
515                id[2] = i2c_smbus_read_byte_data(new_client,
516                                FSCSCY_REG_IDENT_2);
517                id[3] = 0;
518               
519                if (!strcmp(id, "SCY")) {
520                        data->kind = fscscy;
521                        fan_sysfs_attr = 6 * 4;
522                } else if (!strcmp(id, "PEG")) {
523                        data->kind = fscpos;
524                        fan_sysfs_attr = 2 * 4 + 3;
525                } else if (!strcmp(id, "HER")) {
526                        data->kind = fscher;
527                        fan_sysfs_attr = 3 * 4;
528                } else if (!strcmp(id, "HMD")) {
529                        data->kind = fschmd;
530                        fan_sysfs_attr = 5 * 4;
531                } else
532                        goto exit_free;
533        } else
534                data->kind = kind;
535
536        /* i2c kind goes from 1-4, we want from 0-3 to address arrays */
537        data->kind--;
538
539        /* Tell the I2C layer a new client has arrived */
540        if ((err = i2c_attach_client(new_client)))
541                goto exit_free;
542               
543        for (i = 0; i < ARRAY_SIZE(fscscy_attr); i++) {
544                err = device_create_file(&new_client->dev,
545                                        &fscscy_attr[i].dev_attr);
546                if (err)
547                        goto exit_remove_files;
548        }
549
550        for (i = 0; i < (FSCSCY_NO_TEMP_SENSORS[data->kind] * 4); i++) {
551                err = device_create_file(&new_client->dev,
552                                        &fscscy_temp_attr[i].dev_attr);
553                if (err)
554                        goto exit_remove_files;
555        }
556
557        for (i = 0; i < fan_sysfs_attr; i++) {
558                err = device_create_file(&new_client->dev,
559                                        &fscscy_fan_attr[i].dev_attr);
560                if (err)
561                        goto exit_remove_files;
562        }
563
564        data->class_dev = hwmon_device_register(&new_client->dev);
565        if (IS_ERR(data->class_dev)) {
566                err = PTR_ERR(data->class_dev);
567                goto exit_remove_files;
568        }
569
570        revision = i2c_smbus_read_byte_data(new_client, FSCSCY_REG_REVISION);
571        printk(KERN_INFO "fscscy: Detected FSC %s chip, revision: %d\n",
572                names[data->kind], (int) revision);
573
574        return 0;
575
576exit_remove_files:
577        for (i = 0; i < ARRAY_SIZE(fscscy_attr); i++)
578                device_remove_file(&new_client->dev, &fscscy_attr[i].dev_attr);
579        for (i = 0; i < (FSCSCY_NO_TEMP_SENSORS[data->kind] * 4); i++)
580                device_remove_file(&new_client->dev,
581                                        &fscscy_temp_attr[i].dev_attr);
582        for (i = 0; i < fan_sysfs_attr; i++)
583                device_remove_file(&new_client->dev,
584                                        &fscscy_fan_attr[i].dev_attr);
585        i2c_detach_client(new_client);
586exit_free:
587        kfree(data);
588        return err;
589}
590
591static int fscscy_attach_adapter(struct i2c_adapter *adapter)
592{
593        if (!(adapter->class & I2C_CLASS_HWMON))
594                return 0;
595        return i2c_probe(adapter, &addr_data, fscscy_detect);
596}
597
598static int fscscy_detach_client(struct i2c_client *client)
599{
600        struct fscscy_data *data = i2c_get_clientdata(client);
601        int i, err;
602
603        hwmon_device_unregister(data->class_dev);
604        for (i = 0; i < ARRAY_SIZE(fscscy_attr); i++)
605                device_remove_file(&client->dev, &fscscy_attr[i].dev_attr);
606        for (i = 0; i < (FSCSCY_NO_TEMP_SENSORS[data->kind] * 4); i++)
607                device_remove_file(&client->dev,
608                                        &fscscy_temp_attr[i].dev_attr);
609        for (i = 0; i < (FSCSCY_NO_FAN_SENSORS[data->kind] * 4); i++)
610                device_remove_file(&client->dev,
611                                        &fscscy_fan_attr[i].dev_attr);
612
613        if ((err = i2c_detach_client(client)))
614                return err;
615
616        kfree(data);
617        return 0;
618}
619
620static struct fscscy_data *fscscy_update_device(struct device *dev)
621{
622        struct i2c_client *client = to_i2c_client(dev);
623        struct fscscy_data *data = i2c_get_clientdata(client);
624        int i;
625
626        mutex_lock(&data->update_lock);
627
628        if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
629
630                dev_dbg(&client->dev, "Starting fscscy update\n");
631               
632                for (i = 0; i < FSCSCY_NO_TEMP_SENSORS[data->kind]; i++) {
633                        data->temp_act[i] = i2c_smbus_read_byte_data(client,
634                                        FSCSCY_REG_TEMP_ACT[data->kind][i]);
635                        data->temp_status[i] = i2c_smbus_read_byte_data(client,
636                                        FSCSCY_REG_TEMP_STATE[data->kind][i]);
637                        data->temp_max[i] = i2c_smbus_read_byte_data(client,
638                                        FSCSCY_REG_TEMP_LIMIT[data->kind][i]);
639                               
640                        /* reset alarm if the alarm condition is gone,
641                           the chip doesn't do this itself */
642                        if ((data->temp_status[i] & 0x02) &&
643                                        data->temp_act[i] < data->temp_max[i])
644                                i2c_smbus_write_byte_data(client,
645                                        FSCSCY_REG_TEMP_STATE[data->kind][i],
646                                        0x02);
647                }
648                                       
649                for (i = 0; i < FSCSCY_NO_FAN_SENSORS[data->kind]; i++) {
650                        data->fan_act[i] = i2c_smbus_read_byte_data(client,
651                                        FSCSCY_REG_FAN_ACT[data->kind][i]);
652                        data->fan_status[i] = i2c_smbus_read_byte_data(client,
653                                        FSCSCY_REG_FAN_STATE[data->kind][i]);
654                        data->fan_ripple[i] = i2c_smbus_read_byte_data(client,
655                                        FSCSCY_REG_FAN_RIPPLE[data->kind][i]);
656
657                        /* The fscpos third doesn't have a fan_min */
658                        if (FSCSCY_REG_FAN_MIN[data->kind][i])
659                                data->fan_min[i] = i2c_smbus_read_byte_data(
660                                        client,
661                                        FSCSCY_REG_FAN_MIN[data->kind][i]);
662
663                        /* reset fan status if speed is back to > 0 */
664                        if ((data->fan_status[i] & 0x04) && data->fan_act[i])
665                                i2c_smbus_write_byte_data(client,
666                                        FSCSCY_REG_FAN_STATE[data->kind][i],
667                                        0x04);
668                }
669
670                data->global_control = i2c_smbus_read_byte_data(client,
671                                                FSCSCY_REG_CONTROL);
672
673                data->volt[0] = i2c_smbus_read_byte_data(client,
674                                                FSCSCY_REG_VOLT_12);
675                data->volt[1] = i2c_smbus_read_byte_data(client,
676                                                FSCSCY_REG_VOLT_5);
677                data->volt[2] = i2c_smbus_read_byte_data(client,
678                                                FSCSCY_REG_VOLT_BATT);
679
680                /* To be implemented in the future
681                data->watchdog[0] = i2c_smbus_read_byte_data(client,
682                                                FSCSCY_REG_WDOG_PRESET);
683                data->watchdog[1] = i2c_smbus_read_byte_data(client,
684                                                FSCSCY_REG_WDOG_STATE);
685                data->watchdog[2] = i2c_smbus_read_byte_data(client,
686                                                FSCSCY_REG_WDOG_CONTROL); */
687
688                data->last_updated = jiffies;
689                data->valid = 1;
690        }
691
692        mutex_unlock(&data->update_lock);
693
694        return data;
695}
696
697static int __init fscscy_init(void)
698{
699        return i2c_add_driver(&fscscy_driver);
700}
701
702static void __exit fscscy_exit(void)
703{
704        i2c_del_driver(&fscscy_driver);
705}
706
707MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
708MODULE_DESCRIPTION("FSC Scylla (and Poseidon, Hermes and Heimdall) driver");
709MODULE_LICENSE("GPL");
710
711module_init(fscscy_init);
712module_exit(fscscy_exit);