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

Revision 2867, 11.2 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    xeontemp.c - Part of lm_sensors, Linux kernel modules for hardware
3             monitoring
4    Copyright (c) 1998, 1999,2003  Frodo Looijaard <frodol@dds.nl>,
5    Philip Edelbrock <phil@netroedge.com>, and
6    Mark D. Studebaker <mdsxyz123@yahoo.com>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22
23/* The Xeon temperature sensor looks just like an ADM1021 with the remote
24   sensor only. There is are no ID registers so detection is difficult. */
25
26#include <linux/module.h>
27#include <linux/slab.h>
28#include <linux/i2c.h>
29#include <linux/i2c-proc.h>
30#include <linux/init.h>
31#include "version.h"
32
33#ifndef I2C_DRIVERID_XEONTEMP
34#define I2C_DRIVERID_XEONTEMP   1045
35#endif
36
37/* Addresses to scan */
38static unsigned short normal_i2c[] = { 0x18, 0x1a, 0x29, 0x2b,
39        0x4c, 0x4e, SENSORS_I2C_END
40};
41static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
42static unsigned int normal_isa[] = { SENSORS_ISA_END };
43static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
44
45/* Insmod parameters */
46SENSORS_INSMOD_1(xeontemp);
47
48/* xeontemp constants specified below */
49
50/* The registers */
51/* Read-only */
52#define XEONTEMP_REG_REMOTE_TEMP 0x01
53#define XEONTEMP_REG_STATUS 0x02
54/* These use different addresses for reading/writing */
55#define XEONTEMP_REG_CONFIG_R 0x03
56#define XEONTEMP_REG_CONFIG_W 0x09
57#define XEONTEMP_REG_CONV_RATE_R 0x04
58#define XEONTEMP_REG_CONV_RATE_W 0x0A
59/* limits */
60#define XEONTEMP_REG_REMOTE_TOS_R 0x07
61#define XEONTEMP_REG_REMOTE_TOS_W 0x0D
62#define XEONTEMP_REG_REMOTE_THYST_R 0x08
63#define XEONTEMP_REG_REMOTE_THYST_W 0x0E
64/* write-only */
65#define XEONTEMP_REG_ONESHOT 0x0F
66
67#define XEONTEMP_ALARM_RTEMP (XEONTEMP_ALARM_RTEMP_HIGH | XEONTEMP_ALARM_RTEMP_LOW\
68                             | XEONTEMP_ALARM_RTEMP_NA)
69#define XEONTEMP_ALARM_ALL  XEONTEMP_ALARM_RTEMP
70
71/* Conversions. Rounding and limit checking is only done on the TO_REG
72   variants. Note that you should be a bit careful with which arguments
73   these macros are called: arguments may be evaluated more than once.
74   Fixing this is just not worth it. */
75/* Conversions  note: 1021 uses normal integer signed-byte format*/
76#define TEMP_FROM_REG(val) (val > 127 ? val-256 : val)
77#define TEMP_TO_REG(val)   (SENSORS_LIMIT((val < 0 ? val+256 : val),0,255))
78
79/* Each client has this additional data */
80struct xeontemp_data {
81        struct i2c_client client;
82        int sysctl_id;
83        enum chips type;
84
85        struct semaphore update_lock;
86        char valid;             /* !=0 if following fields are valid */
87        unsigned long last_updated;     /* In jiffies */
88
89        u8 remote_temp, remote_temp_os, remote_temp_hyst, alarms;
90        u8 fail;
91};
92
93static int xeontemp_attach_adapter(struct i2c_adapter *adapter);
94static int xeontemp_detect(struct i2c_adapter *adapter, int address,
95                          unsigned short flags, int kind);
96static void xeontemp_init_client(struct i2c_client *client);
97static int xeontemp_detach_client(struct i2c_client *client);
98static int xeontemp_read_value(struct i2c_client *client, u8 reg);
99static int xeontemp_rd_good(u8 *val, struct i2c_client *client, u8 reg, u8 mask);
100static int xeontemp_write_value(struct i2c_client *client, u8 reg,
101                               u16 value);
102static void xeontemp_remote_temp(struct i2c_client *client, int operation,
103                                int ctl_name, int *nrels_mag,
104                                long *results);
105static void xeontemp_alarms(struct i2c_client *client, int operation,
106                           int ctl_name, int *nrels_mag, long *results);
107static void xeontemp_update_client(struct i2c_client *client);
108
109/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
110static int read_only = 0;
111
112
113/* This is the driver that will be inserted */
114static struct i2c_driver xeontemp_driver = {
115        .name           = "Xeon temp sensor driver",
116        .id             = I2C_DRIVERID_XEONTEMP,
117        .flags          = I2C_DF_NOTIFY,
118        .attach_adapter = xeontemp_attach_adapter,
119        .detach_client  = xeontemp_detach_client,
120};
121
122/* -- SENSORS SYSCTL START -- */
123
124#define XEONTEMP_SYSCTL_REMOTE_TEMP 1201
125#define XEONTEMP_SYSCTL_ALARMS 1203
126
127#define XEONTEMP_ALARM_RTEMP_HIGH 0x10
128#define XEONTEMP_ALARM_RTEMP_LOW 0x08
129#define XEONTEMP_ALARM_RTEMP_NA 0x04
130
131/* -- SENSORS SYSCTL END -- */
132
133/* These files are created for each detected xeontemp. This is just a template;
134   though at first sight, you might think we could use a statically
135   allocated list, we need some way to get back to the parent - which
136   is done through one of the 'extra' fields which are initialized
137   when a new copy is allocated. */
138static ctl_table xeontemp_dir_table_template[] = {
139        {XEONTEMP_SYSCTL_REMOTE_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real,
140         &i2c_sysctl_real, NULL, &xeontemp_remote_temp},
141        {XEONTEMP_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
142         &i2c_sysctl_real, NULL, &xeontemp_alarms},
143        {0}
144};
145
146static int xeontemp_attach_adapter(struct i2c_adapter *adapter)
147{
148        return i2c_detect(adapter, &addr_data, xeontemp_detect);
149}
150
151static int xeontemp_detect(struct i2c_adapter *adapter, int address,
152                          unsigned short flags, int kind)
153{
154        int i;
155        struct i2c_client *new_client;
156        struct xeontemp_data *data;
157        int err = 0;
158        const char *type_name = "";
159        const char *client_name = "";
160
161        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
162                goto error0;
163
164        /* OK. For now, we presume we have a valid client. We now create the
165           client structure, even though we cannot fill it completely yet.
166           But it allows us to access xeontemp_{read,write}_value. */
167
168        if (!(data = kmalloc(sizeof(struct xeontemp_data), GFP_KERNEL))) {
169                err = -ENOMEM;
170                goto error0;
171        }
172
173        new_client = &data->client;
174        new_client->addr = address;
175        new_client->data = data;
176        new_client->adapter = adapter;
177        new_client->driver = &xeontemp_driver;
178        new_client->flags = 0;
179
180        /* Now, we do the remaining detection. */
181
182        if (kind < 0) {
183                if (
184                    (xeontemp_read_value(new_client, XEONTEMP_REG_STATUS) &
185                     0x03) != 0x00)
186                        goto error1;
187        }
188
189        /* Determine the chip type. */
190
191        if (kind <= 0) {
192                kind = xeontemp;
193        }
194
195        type_name = "xeontemp";
196        client_name = "xeon sensors";
197
198        /* Fill in the remaining client fields and put it into the global list */
199        strcpy(new_client->name, client_name);
200        data->type = kind;
201        data->valid = 0;
202        init_MUTEX(&data->update_lock);
203
204        /* Tell the I2C layer a new client has arrived */
205        if ((err = i2c_attach_client(new_client)))
206                goto error3;
207
208        /* Register a new directory entry with module sensors */
209        if ((i = i2c_register_entry(new_client, type_name,
210                                    xeontemp_dir_table_template,
211                                    THIS_MODULE)) < 0) {
212                err = i;
213                goto error4;
214        }
215        data->sysctl_id = i;
216
217        xeontemp_init_client(new_client);
218        return 0;
219
220      error4:
221        i2c_detach_client(new_client);
222      error3:
223      error1:
224        kfree(data);
225      error0:
226        return err;
227}
228
229static void xeontemp_init_client(struct i2c_client *client)
230{
231        /* Enable ADC and disable suspend mode */
232        xeontemp_write_value(client, XEONTEMP_REG_CONFIG_W, 0);
233        /* Set Conversion rate to 1/sec (this can be tinkered with) */
234        xeontemp_write_value(client, XEONTEMP_REG_CONV_RATE_W, 0x04);
235}
236
237static int xeontemp_detach_client(struct i2c_client *client)
238{
239
240        int err;
241
242        i2c_deregister_entry(((struct xeontemp_data *) (client->data))->
243                                 sysctl_id);
244
245        if ((err = i2c_detach_client(client))) {
246                printk
247                    ("xeontemp.o: Client deregistration failed, client not detached.\n");
248                return err;
249        }
250
251        kfree(client->data);
252
253        return 0;
254
255}
256
257
258/* All registers are byte-sized */
259static int xeontemp_read_value(struct i2c_client *client, u8 reg)
260{
261        return i2c_smbus_read_byte_data(client, reg);
262}
263
264/* only update value if read succeeded; set fail bit if failed */
265static int xeontemp_rd_good(u8 *val, struct i2c_client *client, u8 reg, u8 mask)
266{
267        int i;
268        struct xeontemp_data *data = client->data;
269
270        i = i2c_smbus_read_byte_data(client, reg);
271        if (i < 0) {
272                data->fail |= mask;
273                return i;
274        }
275        *val = i;
276        return 0;
277}
278
279static int xeontemp_write_value(struct i2c_client *client, u8 reg, u16 value)
280{
281        if (read_only > 0)
282                return 0;
283
284        return i2c_smbus_write_byte_data(client, reg, value);
285}
286
287static void xeontemp_update_client(struct i2c_client *client)
288{
289        struct xeontemp_data *data = client->data;
290
291        down(&data->update_lock);
292
293        if ((jiffies - data->last_updated > HZ + HZ / 2) ||
294            (jiffies < data->last_updated) || !data->valid) {
295
296#ifdef DEBUG
297                printk("Starting xeontemp update\n");
298#endif
299
300                data->fail = 0;
301                xeontemp_rd_good(&(data->remote_temp), client,
302                                XEONTEMP_REG_REMOTE_TEMP, XEONTEMP_ALARM_RTEMP);
303                xeontemp_rd_good(&(data->remote_temp_os), client,
304                                XEONTEMP_REG_REMOTE_TOS_R, XEONTEMP_ALARM_RTEMP);
305                xeontemp_rd_good(&(data->remote_temp_hyst), client,
306                                XEONTEMP_REG_REMOTE_THYST_R,
307                                XEONTEMP_ALARM_RTEMP);
308                data->alarms = XEONTEMP_ALARM_ALL;
309                if (!xeontemp_rd_good(&(data->alarms), client,
310                                     XEONTEMP_REG_STATUS, 0))
311                        data->alarms &= XEONTEMP_ALARM_ALL;
312                data->last_updated = jiffies;
313                data->valid = 1;
314        }
315
316        up(&data->update_lock);
317}
318
319void xeontemp_remote_temp(struct i2c_client *client, int operation,
320                         int ctl_name, int *nrels_mag, long *results)
321{
322        struct xeontemp_data *data = client->data;
323
324        if (operation == SENSORS_PROC_REAL_INFO)
325                *nrels_mag = 0;
326        else if (operation == SENSORS_PROC_REAL_READ) {
327                xeontemp_update_client(client);
328                results[0] = TEMP_FROM_REG(data->remote_temp_os);
329                results[1] = TEMP_FROM_REG(data->remote_temp_hyst);
330                results[2] = TEMP_FROM_REG(data->remote_temp);
331                *nrels_mag = 3;
332        } else if (operation == SENSORS_PROC_REAL_WRITE) {
333                if (*nrels_mag >= 1) {
334                        data->remote_temp_os = TEMP_TO_REG(results[0]);
335                        xeontemp_write_value(client,
336                                            XEONTEMP_REG_REMOTE_TOS_W,
337                                            data->remote_temp_os);
338                }
339                if (*nrels_mag >= 2) {
340                        data->remote_temp_hyst = TEMP_TO_REG(results[1]);
341                        xeontemp_write_value(client,
342                                            XEONTEMP_REG_REMOTE_THYST_W,
343                                            data->remote_temp_hyst);
344                }
345        }
346}
347
348void xeontemp_alarms(struct i2c_client *client, int operation, int ctl_name,
349                    int *nrels_mag, long *results)
350{
351        struct xeontemp_data *data = client->data;
352        if (operation == SENSORS_PROC_REAL_INFO)
353                *nrels_mag = 0;
354        else if (operation == SENSORS_PROC_REAL_READ) {
355                xeontemp_update_client(client);
356                results[0] = data->alarms | data->fail;
357                *nrels_mag = 1;
358        } else if (operation == SENSORS_PROC_REAL_WRITE) {
359                /* Can't write to it */
360        }
361}
362
363static int __init sm_xeontemp_init(void)
364{
365        printk(KERN_INFO "xeontemp.o version %s (%s)\n", LM_VERSION, LM_DATE);
366        return i2c_add_driver(&xeontemp_driver);
367}
368
369static void __exit sm_xeontemp_exit(void)
370{
371        i2c_del_driver(&xeontemp_driver);
372}
373
374MODULE_AUTHOR
375    ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
376MODULE_DESCRIPTION("xeontemp driver");
377MODULE_LICENSE("GPL");
378
379MODULE_PARM(read_only, "i");
380MODULE_PARM_DESC(read_only, "Don't set any values, read only mode");
381
382module_init(sm_xeontemp_init)
383module_exit(sm_xeontemp_exit)
Note: See TracBrowser for help on using the browser.