root/lm-sensors/trunk/kernel/chips/fscher.c @ 2867

Revision 2867, 25.6 KB (checked in by khali, 8 years ago)

Drop unused client id.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2  fscher.c - Part of lm_sensors, Linux kernel modules for hardware
3  monitoring
4  Copyright (C) 2003, 2004 Reinhard Nissl <rnissl@gmx.de>
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   fujitsu siemens hermes chip,
23   module based on fscpos.c
24   Copyright (C) 2000 Hermann Jung <hej@odn.de>
25   Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
26   and Philip Edelbrock <phil@netroedge.com>
27*/
28
29#include <linux/module.h>
30#include <linux/slab.h>
31#include <linux/i2c.h>
32#include <linux/i2c-proc.h>
33#include <linux/init.h>
34#include "version.h"
35
36#ifndef I2C_DRIVERID_FSCHER
37#define I2C_DRIVERID_FSCHER             1046
38#endif
39
40/* Addresses to scan */
41static unsigned short normal_i2c[] = { 0x73, SENSORS_I2C_END };
42static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
43static unsigned int normal_isa[] = { SENSORS_ISA_END };
44static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
45
46/* Insmod parameters */
47SENSORS_INSMOD_1(fscher);
48
49/* The FSCHER registers */
50
51/* chip identification */
52#define FSCHER_REG_IDENT_0       0x00
53#define FSCHER_REG_IDENT_1       0x01
54#define FSCHER_REG_IDENT_2       0x02
55#define FSCHER_REG_REVISION      0x03
56
57/* global control and status */
58#define FSCHER_REG_EVENT_STATE   0x04
59#define FSCHER_REG_CONTROL       0x05
60
61/* watchdog */
62#define FSCHER_REG_WDOG_PRESET   0x28
63#define FSCHER_REG_WDOG_STATE    0x23
64#define FSCHER_REG_WDOG_CONTROL  0x21
65
66/* fan 0  */
67#define FSCHER_REG_FAN0_MIN      0x55
68#define FSCHER_REG_FAN0_ACT      0x0e
69#define FSCHER_REG_FAN0_STATE    0x0d
70#define FSCHER_REG_FAN0_RIPPLE   0x0f
71
72/* fan 1  */
73#define FSCHER_REG_FAN1_MIN      0x65
74#define FSCHER_REG_FAN1_ACT      0x6b
75#define FSCHER_REG_FAN1_STATE    0x62
76#define FSCHER_REG_FAN1_RIPPLE   0x6f
77
78/* fan 2  */
79#define FSCHER_REG_FAN2_MIN      0xb5
80#define FSCHER_REG_FAN2_ACT      0xbb
81#define FSCHER_REG_FAN2_STATE    0xb2
82#define FSCHER_REG_FAN2_RIPPLE   0xbf
83
84/* voltage supervision */
85#define FSCHER_REG_VOLT_12       0x45
86#define FSCHER_REG_VOLT_5        0x42
87#define FSCHER_REG_VOLT_BATT     0x48
88
89/* temperatures */
90/* sensor 0 */
91#define FSCHER_REG_TEMP0_ACT     0x64
92#define FSCHER_REG_TEMP0_STATE   0x71
93
94/* sensor 1 */
95#define FSCHER_REG_TEMP1_ACT     0x32
96#define FSCHER_REG_TEMP1_STATE   0x81
97
98/* sensor 2 */
99#define FSCHER_REG_TEMP2_ACT     0x35
100#define FSCHER_REG_TEMP2_STATE   0x91
101
102
103
104/* Initial limits */
105
106/* For each registered FSCHER, we need to keep some data in memory. That
107   data is pointed to by fscher_list[NR]->data. The structure itself is
108   dynamically allocated, at the same time when a new fscher client is
109   allocated. */
110struct fscher_data {
111  struct i2c_client client;
112  int sysctl_id;
113
114  struct semaphore update_lock;
115  char valid;        /* !=0 if following fields are valid */
116  unsigned long last_updated;   /* In jiffies */
117
118  u8  revision;        /* revision of chip */
119  u8  global_event;    /* global event status */
120  u8  global_control;  /* global control register */
121  u8  watchdog[3];     /* watchdog */
122  u8  volt[3];         /* 12, 5, battery current */ 
123  u8  temp_act[3];     /* temperature */
124  u8  temp_status[3];  /* status of sensor */
125  u8  fan_act[3];      /* fans revolutions per second */
126  u8  fan_status[3];   /* fan status */
127  u8  fan_min[3];      /* fan min value for rps */
128  u8  fan_ripple[3];   /* divider for rps */
129};
130
131
132static int fscher_attach_adapter(struct i2c_adapter *adapter);
133static int fscher_detect(struct i2c_adapter *adapter, int address,
134                         unsigned short flags, int kind);
135static int fscher_detach_client(struct i2c_client *client);
136
137static int fscher_read_value(struct i2c_client *client, u8 register);
138static int fscher_write_value(struct i2c_client *client, u8 register,
139                              u8 value);
140static void fscher_update_client(struct i2c_client *client);
141static void fscher_init_client(struct i2c_client *client);
142
143
144static void fscher_in(struct i2c_client *client, int operation, int ctl_name,
145                      int *nrels_mag, long *results);
146static void fscher_pwm(struct i2c_client *client, int operation,
147                       int ctl_name, int *nrels_mag, long *results);
148static void fscher_pwm_internal(struct i2c_client *client, int operation,
149                                int ctl_name, int *nrels_mag, long *results, 
150                                int nr, int reg_min);
151static void fscher_fan(struct i2c_client *client, int operation,
152                       int ctl_name, int *nrels_mag, long *results);
153static void fscher_fan_internal(struct i2c_client *client, int operation,
154                                int ctl_name, int *nrels_mag, long *results, 
155                                int nr, int reg_state, int res_ripple);
156static void fscher_temp(struct i2c_client *client, int operation,
157                        int ctl_name, int *nrels_mag, long *results);
158static void fscher_volt(struct i2c_client *client, int operation,
159                        int ctl_name, int *nrels_mag, long *results);
160static void fscher_wdog(struct i2c_client *client, int operation,
161                        int ctl_name, int *nrels_mag, long *results);
162
163static struct i2c_driver fscher_driver = {
164  .name                 = "FSCHER sensor driver",
165  .id                   = I2C_DRIVERID_FSCHER,
166  .flags                = I2C_DF_NOTIFY,
167  .attach_adapter       = fscher_attach_adapter,
168  .detach_client        = fscher_detach_client,
169};
170
171/* -- SENSORS SYSCTL START -- */
172#define FSCHER_SYSCTL_VOLT0    1000       /* 12 volt supply */
173#define FSCHER_SYSCTL_VOLT1    1001       /* 5 volt supply */
174#define FSCHER_SYSCTL_VOLT2    1002       /* batterie voltage */
175#define FSCHER_SYSCTL_FAN0     1101       /* state, ripple, actual value
176                                             fan 0 */
177#define FSCHER_SYSCTL_FAN1     1102       /* state, ripple, actual value
178                                             fan 1 */
179#define FSCHER_SYSCTL_FAN2     1103       /* state, ripple, actual value
180                                             fan 2 */
181#define FSCHER_SYSCTL_TEMP0    1201       /* state and value of sensor 0,
182                                             cpu die */
183#define FSCHER_SYSCTL_TEMP1    1202       /* state and value of sensor 1,
184                                             motherboard */
185#define FSCHER_SYSCTL_TEMP2    1203       /* state and value of sensor 2,
186                                             chassis */
187#define FSCHER_SYSCTL_PWM0     1301       /* min fan 0 */
188#define FSCHER_SYSCTL_PWM1     1302       /* min fan 1 */
189#define FSCHER_SYSCTL_PWM2     1303       /* min fan 2 */
190#define FSCHER_SYSCTL_REV      2000       /* revision */
191#define FSCHER_SYSCTL_EVENT    2001       /* global event status */
192#define FSCHER_SYSCTL_CONTROL  2002       /* global control byte */
193#define FSCHER_SYSCTL_WDOG     2003       /* watch dog preset, state and
194                                             control */
195/* -- SENSORS SYSCTL END -- */
196
197/* These files are created for each detected FSCHER. This is just a template;
198   though at first sight, you might think we could use a statically
199   allocated list, we need some way to get back to the parent - which
200   is done through one of the 'extra' fields which are initialized
201   when a new copy is allocated. */
202static ctl_table fscher_dir_table_template[] = {
203  {FSCHER_SYSCTL_REV, "rev", NULL, 0, 0444, NULL, &i2c_proc_real,
204   &i2c_sysctl_real, NULL, &fscher_in},
205  {FSCHER_SYSCTL_EVENT, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
206   &i2c_sysctl_real, NULL, &fscher_in},
207  {FSCHER_SYSCTL_CONTROL, "control", NULL, 0, 0644, NULL, &i2c_proc_real,
208   &i2c_sysctl_real, NULL, &fscher_in},
209  {FSCHER_SYSCTL_TEMP0, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
210   &i2c_sysctl_real, NULL, &fscher_temp},
211  {FSCHER_SYSCTL_TEMP1, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
212   &i2c_sysctl_real, NULL, &fscher_temp},
213  {FSCHER_SYSCTL_TEMP2, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
214   &i2c_sysctl_real, NULL, &fscher_temp},
215  {FSCHER_SYSCTL_VOLT0, "in0", NULL, 0, 0444, NULL, &i2c_proc_real,
216   &i2c_sysctl_real, NULL, &fscher_volt},
217  {FSCHER_SYSCTL_VOLT1, "in1", NULL, 0, 0444, NULL, &i2c_proc_real,
218   &i2c_sysctl_real, NULL, &fscher_volt},
219  {FSCHER_SYSCTL_VOLT2, "in2", NULL, 0, 0444, NULL, &i2c_proc_real,
220   &i2c_sysctl_real, NULL, &fscher_volt},
221  {FSCHER_SYSCTL_FAN0, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
222   &i2c_sysctl_real, NULL, &fscher_fan},
223  {FSCHER_SYSCTL_FAN1, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
224   &i2c_sysctl_real, NULL, &fscher_fan},
225  {FSCHER_SYSCTL_FAN2, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
226   &i2c_sysctl_real, NULL, &fscher_fan},
227  {FSCHER_SYSCTL_PWM0, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
228   &i2c_sysctl_real, NULL, &fscher_pwm},
229  {FSCHER_SYSCTL_PWM1, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
230   &i2c_sysctl_real, NULL, &fscher_pwm},
231  {FSCHER_SYSCTL_PWM2, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real,
232   &i2c_sysctl_real, NULL, &fscher_pwm},
233  {FSCHER_SYSCTL_WDOG, "wdog", NULL, 0, 0644, NULL, &i2c_proc_real,
234   &i2c_sysctl_real, NULL, &fscher_wdog},
235  {0}
236};
237
238static int fscher_attach_adapter(struct i2c_adapter *adapter)
239{
240  return i2c_detect(adapter, &addr_data, fscher_detect);
241}
242
243int fscher_detect(struct i2c_adapter *adapter, int address,
244                  unsigned short flags, int kind)
245{
246  int i;
247  struct i2c_client *new_client;
248  struct fscher_data *data;
249  int err = 0;
250  const char *type_name, *client_name;
251
252  /* Make sure we aren't probing the ISA bus!! This is just a safety
253     check at this moment; i2c_detect really won't call us. */
254#ifdef DEBUG
255  if (i2c_is_isa_adapter(adapter)) {
256    printk("fscher.o: fscher_detect called for an ISA bus adapter?!?\n");
257    return 0;
258  }
259#endif
260
261  if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
262    goto ERROR0;
263
264  /* OK. For now, we presume we have a valid client. We now create the
265     client structure, even though we cannot fill it completely yet.
266     But it allows us to access fscher_{read,write}_value. */
267  if (!(data = kmalloc(sizeof(struct fscher_data), GFP_KERNEL))) {
268    err = -ENOMEM;
269    goto ERROR0;
270  }
271
272  new_client = &data->client;
273  new_client->addr = address;
274  new_client->data = data;
275  new_client->adapter = adapter;
276  new_client->driver = &fscher_driver;
277  new_client->flags = 0;
278
279  /* Do the remaining detection unless force or force_fscher parameter */
280  if (kind < 0) {
281    if (fscher_read_value(new_client, FSCHER_REG_IDENT_0) != 0x48) /* 'H' */
282      goto ERROR1;
283    if (fscher_read_value(new_client, FSCHER_REG_IDENT_1) != 0x45) /* 'E' */
284      goto ERROR1;
285    if (fscher_read_value(new_client, FSCHER_REG_IDENT_2) != 0x52) /* 'R' */
286      goto ERROR1;
287  }
288
289  kind = fscher;
290
291  type_name = "fscher";
292  client_name = "fsc hermes chip";
293
294  /* Fill in the remaining client fields and put it into the
295     global list */
296  strcpy(new_client->name, client_name);
297  data->valid = 0;
298  init_MUTEX(&data->update_lock);
299
300  /* Tell the I2C layer a new client has arrived */
301  if ((err = i2c_attach_client(new_client)))
302    goto ERROR3;
303
304  /* Register a new directory entry with module sensors */
305  if ((i = i2c_register_entry(new_client, type_name,
306                              fscher_dir_table_template,
307                              THIS_MODULE)) < 0) {
308    err = i;
309    goto ERROR4;
310  }
311  data->sysctl_id = i;
312
313  fscher_init_client(new_client);
314  return 0;
315
316/* OK, this is not exactly good programming practice, usually. But it is
317   very code-efficient in this case. */
318 ERROR4:
319  i2c_detach_client(new_client);
320 ERROR3:
321 ERROR1:
322  kfree(data);
323 ERROR0:
324  return err;
325}
326
327static int fscher_detach_client(struct i2c_client *client)
328{
329  int err;
330
331  i2c_deregister_entry(((struct fscher_data *) (client->data))->sysctl_id);
332
333  if ((err = i2c_detach_client(client))) {
334    printk("fscher.o: Client deregistration failed, client not detached.\n");
335    return err;
336  }
337
338  kfree(client->data);
339
340  return 0;
341}
342
343static int fscher_read_value(struct i2c_client *client, u8 reg)
344{
345#ifdef DEBUG
346  printk("fscher: read reg 0x%02x\n",reg);
347#endif
348  return i2c_smbus_read_byte_data(client, reg);
349}
350
351static int fscher_write_value(struct i2c_client *client, u8 reg, u8 value)
352{
353#ifdef DEBUG
354  printk("fscher: write reg 0x%02x, val 0x%02x\n",reg, value);
355#endif
356  return i2c_smbus_write_byte_data(client, reg, value);
357}
358
359/* Called when we have found a new FSCHER. It should set limits, etc. */
360static void fscher_init_client(struct i2c_client *client)
361{
362  struct fscher_data *data = client->data;
363
364  /* read revision from chip */
365  data->revision =  fscher_read_value(client,FSCHER_REG_REVISION);
366}
367
368static void fscher_update_client(struct i2c_client *client)
369{
370  struct fscher_data *data = client->data;
371
372  down(&data->update_lock);
373
374  if ((jiffies - data->last_updated > 2 * HZ) ||
375      (jiffies < data->last_updated) || !data->valid) {
376
377#ifdef DEBUG
378    printk("Starting fscher update\n");
379#endif
380    data->temp_act[0] = fscher_read_value(client, FSCHER_REG_TEMP0_ACT);
381    data->temp_act[1] = fscher_read_value(client, FSCHER_REG_TEMP1_ACT);
382    data->temp_act[2] = fscher_read_value(client, FSCHER_REG_TEMP2_ACT);
383    data->temp_status[0] = fscher_read_value(client, FSCHER_REG_TEMP0_STATE);
384    data->temp_status[1] = fscher_read_value(client, FSCHER_REG_TEMP1_STATE);
385    data->temp_status[2] = fscher_read_value(client, FSCHER_REG_TEMP2_STATE);
386
387    data->volt[0] = fscher_read_value(client, FSCHER_REG_VOLT_12);
388    data->volt[1] = fscher_read_value(client, FSCHER_REG_VOLT_5);
389    data->volt[2] = fscher_read_value(client, FSCHER_REG_VOLT_BATT);
390
391    data->fan_act[0] = fscher_read_value(client, FSCHER_REG_FAN0_ACT);
392    data->fan_act[1] = fscher_read_value(client, FSCHER_REG_FAN1_ACT);
393    data->fan_act[2] = fscher_read_value(client, FSCHER_REG_FAN2_ACT);
394    data->fan_status[0] = fscher_read_value(client, FSCHER_REG_FAN0_STATE);
395    data->fan_status[1] = fscher_read_value(client, FSCHER_REG_FAN1_STATE);
396    data->fan_status[2] = fscher_read_value(client, FSCHER_REG_FAN2_STATE);
397    data->fan_min[0] = fscher_read_value(client, FSCHER_REG_FAN0_MIN);
398    data->fan_min[1] = fscher_read_value(client, FSCHER_REG_FAN1_MIN);
399    data->fan_min[2] = fscher_read_value(client, FSCHER_REG_FAN2_MIN);
400    data->fan_ripple[0] = fscher_read_value(client, FSCHER_REG_FAN0_RIPPLE);
401    data->fan_ripple[1] = fscher_read_value(client, FSCHER_REG_FAN1_RIPPLE);
402    data->fan_ripple[2] = fscher_read_value(client, FSCHER_REG_FAN2_RIPPLE);
403
404    data->watchdog[0] = fscher_read_value(client, FSCHER_REG_WDOG_PRESET);
405    data->watchdog[1] = fscher_read_value(client, FSCHER_REG_WDOG_STATE);
406    data->watchdog[2] = fscher_read_value(client, FSCHER_REG_WDOG_CONTROL);
407
408    data->global_event = fscher_read_value(client, FSCHER_REG_EVENT_STATE);
409
410    data->last_updated = jiffies;
411    data->valid = 1;                 
412  }
413
414  up(&data->update_lock);
415}
416
417
418/* The next few functions are the call-back functions of the /proc/sys and
419   sysctl files. Which function is used is defined in the ctl_table in
420   the extra1 field.
421   Each function must return the magnitude (power of 10 to divide the date
422   with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
423   put a maximum of *nrels elements in results reflecting the data of this
424   file, and set *nrels to the number it actually put in it, if operation==
425   SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
426   results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
427   Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
428   large enough (by checking the incoming value of *nrels). This is not very
429   good practice, but as long as you put less than about 5 values in results,
430   you can assume it is large enough. */
431void fscher_in(struct i2c_client *client, int operation, int ctl_name,
432               int *nrels_mag, long *results)
433{
434  struct fscher_data *data = client->data;
435
436  if (operation == SENSORS_PROC_REAL_INFO)
437    *nrels_mag = 0;
438  else if (operation == SENSORS_PROC_REAL_READ) {
439    fscher_update_client(client);
440    switch(ctl_name) {
441    case FSCHER_SYSCTL_REV:
442      results[0] = data->revision ;
443      break;
444    case FSCHER_SYSCTL_EVENT:
445      /* bits 6, 5 and 2 are reserved => mask with 0x9b */
446      results[0] = data->global_event & 0x9b;
447      break;
448    case FSCHER_SYSCTL_CONTROL:
449      results[0] = data->global_control & 0x01;
450      break;
451    default:
452      printk("fscher: ctl_name %d not supported\n", ctl_name);
453      *nrels_mag = 0;
454      return;
455    }
456    *nrels_mag = 1;
457  } else if (operation == SENSORS_PROC_REAL_WRITE) {
458    if((ctl_name == FSCHER_SYSCTL_CONTROL) && (*nrels_mag >= 1)) {
459      data->global_control = (results[0] & 0x01);
460      printk("fscher: writing 0x%02x to global_control\n",
461             data->global_control);
462      fscher_write_value(client,FSCHER_REG_CONTROL,
463                         data->global_control);
464    }
465    else
466      printk("fscher: writing to chip not supported\n");
467  }
468}
469
470
471#define TEMP_FROM_REG(val)    (val-128)
472
473void fscher_temp(struct i2c_client *client, int operation, int ctl_name,
474                 int *nrels_mag, long *results)
475{
476  struct fscher_data *data = client->data;
477
478  if (operation == SENSORS_PROC_REAL_INFO)
479    *nrels_mag = 0;
480  else if (operation == SENSORS_PROC_REAL_READ) {
481    fscher_update_client(client);
482    switch(ctl_name) {
483    case FSCHER_SYSCTL_TEMP0:
484      results[0] = data->temp_status[0] & 0x03;
485      results[1] = TEMP_FROM_REG(data->temp_act[0]);
486      break;
487    case FSCHER_SYSCTL_TEMP1:
488      results[0] = data->temp_status[1] & 0x03;
489      results[1] = TEMP_FROM_REG(data->temp_act[1]);
490      break;
491    case FSCHER_SYSCTL_TEMP2:
492      results[0] = data->temp_status[2] & 0x03;
493      results[1] = TEMP_FROM_REG(data->temp_act[2]);
494      break;
495    default:
496      printk("fscher: ctl_name %d not supported\n", ctl_name);
497      *nrels_mag = 0;
498      return;
499    }
500    *nrels_mag = 2;
501  } else if (operation == SENSORS_PROC_REAL_WRITE) {
502    if(*nrels_mag >= 1) {
503      switch(ctl_name) {
504      case FSCHER_SYSCTL_TEMP0:
505        data->temp_status[0] = (data->temp_status[0] & ~0x02)
506          | (results[0] & 0x02);
507        printk("fscher: writing value 0x%02x to temp0_status\n",
508               data->temp_status[0]);
509        fscher_write_value(client, FSCHER_REG_TEMP0_STATE,
510                           data->temp_status[0] & 0x02);
511        break;
512      case FSCHER_SYSCTL_TEMP1:
513        data->temp_status[1] = (data->temp_status[1] & ~0x02)
514          | (results[0] & 0x02);
515        printk("fscher: writing value 0x%02x to temp1_status\n",
516               data->temp_status[1]);
517        fscher_write_value(client, FSCHER_REG_TEMP1_STATE,
518                           data->temp_status[1] & 0x02);
519        break;
520      case FSCHER_SYSCTL_TEMP2:
521        data->temp_status[2] = (data->temp_status[2] & ~0x02)
522          | (results[0] & 0x02);
523        printk("fscher: writing value 0x%02x to temp2_status\n",
524               data->temp_status[2]);
525        fscher_write_value(client, FSCHER_REG_TEMP2_STATE,
526                           data->temp_status[2] & 0x02);
527        break;
528      default:
529        printk("fscher: ctl_name %d not supported\n",ctl_name);
530      }
531    }
532    else
533      printk("fscher: writing to chip not supported\n");
534  }
535}
536
537/*
538 * The final conversion is specified in sensors.conf, as it depends on
539 * mainboard specific values. We export the registers contents as
540 * pseudo-hundredths-of-Volts (range 0V - 2.55V). Not that it makes much
541 * sense per se, but it minimizes the conversions count and keeps the
542 * values within a usual range.
543 */
544void fscher_volt(struct i2c_client *client, int operation, int ctl_name,
545                 int *nrels_mag, long *results)
546{
547  struct fscher_data *data = client->data;
548
549  if (operation == SENSORS_PROC_REAL_INFO)
550    *nrels_mag = 2;
551  else if (operation == SENSORS_PROC_REAL_READ) {
552    fscher_update_client(client);
553    switch(ctl_name) {
554    case FSCHER_SYSCTL_VOLT0:
555      results[0] = data->volt[0];
556      break;
557    case FSCHER_SYSCTL_VOLT1:
558      results[0] = data->volt[1];
559      break;
560    case FSCHER_SYSCTL_VOLT2:
561      results[0] = data->volt[2];
562      break;
563    default:
564      printk("fscher: ctl_name %d not supported\n", ctl_name);
565      *nrels_mag = 0;
566      return;
567    }
568    *nrels_mag = 1;
569  } else if (operation == SENSORS_PROC_REAL_WRITE) {
570    printk("fscher: writing to chip not supported\n");
571  }
572}
573
574void fscher_pwm(struct i2c_client *client, int operation, int ctl_name,
575                int *nrels_mag, long *results)
576{
577
578  switch(ctl_name) {
579  case FSCHER_SYSCTL_PWM0:
580    fscher_pwm_internal(client,operation,ctl_name,nrels_mag,results,
581                        0,FSCHER_REG_FAN0_MIN);
582    break;
583  case FSCHER_SYSCTL_PWM1:
584    fscher_pwm_internal(client,operation,ctl_name,nrels_mag,results,
585                        1,FSCHER_REG_FAN1_MIN);
586    break;
587  case FSCHER_SYSCTL_PWM2:
588    fscher_pwm_internal(client,operation,ctl_name,nrels_mag,results,
589                        2,FSCHER_REG_FAN2_MIN);
590    break;
591  default:
592    printk("fscher: illegal pwm nr %d\n",ctl_name);
593  }
594}
595                       
596void fscher_pwm_internal(struct i2c_client *client, int operation,
597                         int ctl_name, int *nrels_mag, long *results,
598                         int nr, int reg_min)
599{
600  struct fscher_data *data = client->data;
601
602  if (operation == SENSORS_PROC_REAL_INFO)
603    *nrels_mag = 0;
604  else if (operation == SENSORS_PROC_REAL_READ) {
605    fscher_update_client(client);
606    results[0] = data->fan_min[nr];
607    *nrels_mag = 1;
608  } else if (operation == SENSORS_PROC_REAL_WRITE) {
609    if(*nrels_mag >= 1) { 
610      data->fan_min[nr] = results[0];
611      printk("fscher: writing value 0x%02x to fan%d_min\n",
612             data->fan_min[nr],nr);
613      fscher_write_value(client,reg_min,data->fan_min[nr]);
614    }
615  }
616}
617
618void fscher_fan(struct i2c_client *client, int operation, int ctl_name,
619                int *nrels_mag, long *results)
620{
621  switch(ctl_name) {
622  case FSCHER_SYSCTL_FAN0:
623    fscher_fan_internal(client,operation,ctl_name,nrels_mag,results,
624                        0,FSCHER_REG_FAN0_STATE, FSCHER_REG_FAN0_RIPPLE);
625    break;
626  case FSCHER_SYSCTL_FAN1:
627    fscher_fan_internal(client,operation,ctl_name,nrels_mag,results,
628                        1,FSCHER_REG_FAN1_STATE, FSCHER_REG_FAN1_RIPPLE);
629    break;
630  case FSCHER_SYSCTL_FAN2:
631    fscher_fan_internal(client,operation,ctl_name,nrels_mag,results,
632                        2,FSCHER_REG_FAN2_STATE, FSCHER_REG_FAN2_RIPPLE);
633    break;
634  default:
635    printk("fscher: illegal fan nr %d\n",ctl_name);
636  }
637}
638                       
639#define RPM_FROM_REG(val)   (val*60)
640
641void fscher_fan_internal(struct i2c_client *client, int operation,
642                         int ctl_name, int *nrels_mag, long *results,
643                         int nr, int reg_state, int reg_ripple)
644{
645  struct fscher_data *data = client->data;
646
647  if (operation == SENSORS_PROC_REAL_INFO)
648    *nrels_mag = 0;
649  else if (operation == SENSORS_PROC_REAL_READ) {
650    fscher_update_client(client);
651    results[0] = data->fan_status[nr] & 0x04;
652    results[1] = data->fan_ripple[nr] & 0x03;
653    results[2] = RPM_FROM_REG(data->fan_act[nr]);
654    *nrels_mag = 3;
655  } else if (operation == SENSORS_PROC_REAL_WRITE) {
656    if(*nrels_mag >= 1) {
657      data->fan_status[nr] = results[0] & 0x04;
658      printk("fscher: writing value 0x%02x to fan%d_status\n",
659             data->fan_status[nr],nr);
660      fscher_write_value(client,reg_state,data->fan_status[nr]);
661    }
662    if(*nrels_mag >= 2) {
663      if((results[1] & 0x03) == 0) {
664        printk("fscher: fan%d ripple 0 not allowed\n",nr);
665        return;
666      }
667      data->fan_ripple[nr] = results[1] & 0x03;
668      printk("fscher: writing value 0x%02x to fan%d_ripple\n",
669             data->fan_ripple[nr],nr);
670      fscher_write_value(client,reg_ripple,data->fan_ripple[nr]);
671    }   
672  }
673}
674
675void fscher_wdog(struct i2c_client *client, int operation, int ctl_name,
676                 int *nrels_mag, long *results)
677{
678  struct fscher_data *data = client->data;
679
680  if (operation == SENSORS_PROC_REAL_INFO)
681    *nrels_mag = 0;
682  else if (operation == SENSORS_PROC_REAL_READ) {
683    fscher_update_client(client);
684    results[0] = data->watchdog[0] ;
685    results[1] = data->watchdog[1] & 0x02;
686    results[2] = data->watchdog[2] & 0xd0;
687    *nrels_mag = 3;
688  } else if (operation == SENSORS_PROC_REAL_WRITE) {
689    if (*nrels_mag >= 1) {
690      data->watchdog[0] = results[0] & 0xff;
691      printk("fscher: writing value 0x%02x to wdog_preset\n",
692             data->watchdog[0]); 
693      fscher_write_value(client,FSCHER_REG_WDOG_PRESET,data->watchdog[0]);
694    } 
695    if (*nrels_mag >= 2) {
696      data->watchdog[1] = results[1] & 0x02;
697      printk("fscher: writing value 0x%02x to wdog_state\n",
698             data->watchdog[1]); 
699      fscher_write_value(client,FSCHER_REG_WDOG_STATE,data->watchdog[1]);
700    }
701    if (*nrels_mag >= 3) {
702      data->watchdog[2] = results[2] & 0xf0;
703      printk("fscher: writing value 0x%02x to wdog_control\n",
704             data->watchdog[2]); 
705      fscher_write_value(client,FSCHER_REG_WDOG_CONTROL,data->watchdog[2]);
706    }
707  }
708}
709
710static int __init sm_fscher_init(void)
711{
712  printk("fscher.o version %s (%s)\n", LM_VERSION, LM_DATE);
713  return i2c_add_driver(&fscher_driver);
714}
715
716static void __exit sm_fscher_exit(void)
717{
718  i2c_del_driver(&fscher_driver);
719}
720
721
722
723MODULE_AUTHOR("Reinhard Nissl <rnissl@gmx.de> based on work from Hermann"
724              " Jung <hej@odn.de>, Frodo Looijaard <frodol@dds.nl> and"
725              " Philip Edelbrock <phil@netroedge.com>");
726MODULE_DESCRIPTION("fujitsu siemens hermes chip driver");
727MODULE_LICENSE("GPL");
728
729module_init(sm_fscher_init);
730module_exit(sm_fscher_exit);
Note: See TracBrowser for help on using the browser.