root/lm-sensors/trunk/kernel/chips/max1619.c @ 2784

Revision 2784, 13.2 KB (checked in by khali, 8 years ago)

Restore controlling_mod argument to i2c_register_entry(). This
is needed to properly lock chip drivers in memory while anyone uses their
/proc entries. This also brings back compatibility with the 2.4 Linux
kernel.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * max1619.c - Part of lm_sensors, Linux kernel modules for hardware
3 *             monitoring
4 * Copyright (C) 2004 Alexey Fisher <fishor@mail.ru>
5 *                    Jean Delvare <khali@linux-fr.org>
6 *
7 * Copied from lm90.c:
8 * Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
9 *
10 * The MAX1619 is a sensor chip made by Maxim. It reports up to two
11 * temperatures (its own plus up to one external one).
12 * Complete datasheet can be obtained from Maxim's website at:
13 *   http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 */
29
30#include <linux/module.h>
31#include <linux/slab.h>
32#include <linux/i2c.h>
33#include <linux/i2c-proc.h>
34#include <linux/init.h>
35#include "version.h"
36
37/*
38 * Addresses to scan
39 */
40
41static unsigned short normal_i2c[] = { SENSORS_I2C_END };
42static unsigned short normal_i2c_range[] = {0x18, 0x1a, 0x29, 0x2b,
43        0x4c, 0x4e, SENSORS_I2C_END };
44static unsigned int normal_isa[] = { SENSORS_ISA_END };
45static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
46
47/*
48 * Insmod parameters
49 */
50
51SENSORS_INSMOD_1(max1619);
52
53/*
54 * The max1619 registers
55 */
56
57#define MAX1619_REG_R_CONFIG            0x03
58#define MAX1619_REG_W_CONFIG            0x09
59#define MAX1619_REG_R_CONVRATE          0x04
60#define MAX1619_REG_W_CONVRATE          0x0A
61#define MAX1619_REG_R_STATUS            0x02
62#define MAX1619_REG_R_LOCAL_TEMP        0x00
63#define MAX1619_REG_R_REMOTE_TEMP       0x01
64#define MAX1619_REG_R_REMOTE_THIGH      0x07
65#define MAX1619_REG_W_REMOTE_THIGH      0x0d
66#define MAX1619_REG_R_REMOTE_TLOW       0x08
67#define MAX1619_REG_W_REMOTE_TLOW       0x0E
68#define MAX1619_REG_R_REMOTE_TMAX       0x10
69#define MAX1619_REG_W_REMOTE_TMAX       0x12
70#define MAX1619_REG_R_REMOTE_THYST      0x11
71#define MAX1619_REG_W_REMOTE_THYST      0x13
72#define MAX1619_REG_R_MAN_ID            0xFE
73#define MAX1619_REG_R_CHIP_ID           0xFF
74
75/*
76 * Conversions and various macros
77 */
78
79#define TEMP_FROM_REG(val)      ((val) & 0x80 ? (val)-0x100 : (val))
80#define TEMP_TO_REG(val)        ((val) < 0 ? (val)+0x100 : (val))
81
82/*
83 * Functions declaration
84 */
85
86static int max1619_attach_adapter(struct i2c_adapter *adapter);
87static int max1619_detect(struct i2c_adapter *adapter, int address,
88        unsigned short flags, int kind);
89static void max1619_init_client(struct i2c_client *client);
90static int max1619_detach_client(struct i2c_client *client);
91static void max1619_local_temp(struct i2c_client *client, int operation,
92        int ctl_name, int *nrels_mag, long *results);
93static void max1619_remote_temp(struct i2c_client *client, int operation,
94        int ctl_name, int *nrels_mag, long *results);
95static void max1619_remote_crit(struct i2c_client *client, int operation,
96        int ctl_name, int *nrels_mag, long *results);
97static void max1619_alarms(struct i2c_client *client, int operation,
98        int ctl_name, int *nrels_mag, long *results);
99
100/*
101 * Driver data (common to all clients)
102 */
103
104static struct i2c_driver max1619_driver = {
105        .name           = "MAX1619 sensor driver",
106        .flags          = I2C_DF_NOTIFY,
107        .attach_adapter = max1619_attach_adapter,
108        .detach_client  = max1619_detach_client
109};
110
111/*
112 * Client data (each client gets its own)
113 */
114
115struct max1619_data {
116        struct i2c_client client;
117        int sysctl_id;
118
119        struct semaphore update_lock;
120        char valid; /* zero until following fields are valid */
121        unsigned long last_updated; /* in jiffies */
122
123        /* register values */
124        u8 local_temp;
125        u8 remote_temp, remote_high, remote_low;
126        u8 remote_hyst, remote_max;
127        u8 alarms;
128};
129
130/*
131 * Proc entries
132 * These files are created for each detected max1619.
133 */
134
135/* -- SENSORS SYSCTL START -- */
136
137#define MAX1619_SYSCTL_LOCAL_TEMP       1200
138#define MAX1619_SYSCTL_REMOTE_TEMP      1201
139#define MAX1619_SYSCTL_REMOTE_CRIT      1202
140#define MAX1619_SYSCTL_ALARMS           1203
141
142#define MAX1619_ALARM_REMOTE_THIGH      0x10
143#define MAX1619_ALARM_REMOTE_TLOW       0x08
144#define MAX1619_ALARM_REMOTE_OPEN       0x04
145#define MAX1619_ALARM_REMOTE_OVERT      0x02
146
147/* -- SENSORS SYSCTL END -- */
148
149
150static ctl_table max1619_dir_table_template[] =
151{
152        {MAX1619_SYSCTL_LOCAL_TEMP, "temp1", NULL, 0, 0444, NULL,
153         &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_local_temp},
154        {MAX1619_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL,
155         &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_remote_temp},
156        {MAX1619_SYSCTL_REMOTE_CRIT,"temp2_crit", NULL, 0, 0644, NULL,
157         &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_remote_crit},
158        {MAX1619_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL,
159         &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_alarms},
160        {0}
161};
162
163/*
164 * Internal variables
165 */
166
167static int max1619_id = 0;
168
169/*
170 * Real code
171 */
172
173static int max1619_attach_adapter(struct i2c_adapter *adapter)
174{
175        return i2c_detect(adapter, &addr_data, max1619_detect);
176}
177
178/*
179 * The following function does more than just detection. If detection
180 * succeeds, it also registers the new chip.
181 */
182static int max1619_detect(struct i2c_adapter *adapter, int address,
183        unsigned short flags, int kind)
184{
185        struct i2c_client *new_client;
186        struct max1619_data *data;
187        int err = 0;
188        const char *type_name = "";
189        const char *client_name = "";
190
191#ifdef DEBUG
192        if (i2c_is_isa_adapter(adapter)) {
193                printk(KERN_DEBUG "max1619.o: Called for an ISA bus "
194                       "adapter, aborting.\n");
195                return 0;
196        }
197#endif
198
199        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
200#ifdef DEBUG
201                printk(KERN_DEBUG "max1619.o: I2C bus doesn't support "
202                       "byte read mode, skipping.\n");
203#endif
204                return 0;
205        }
206
207        if (!(data = kmalloc(sizeof(struct max1619_data), GFP_KERNEL))) {
208                printk(KERN_ERR "max1619.o: Out of memory in "
209                       "max1619_detect (new_client).\n");
210                return -ENOMEM;
211        }
212
213        /*
214         * The common I2C client data is placed right before the
215         * MAX1619-specific data. The MAX1619-specific data is pointed to
216         * by the data field from the I2C client da1ta.
217         */
218
219        new_client = &data->client;
220        new_client->addr = address;
221        new_client->data = data;
222        new_client->adapter = adapter;
223        new_client->driver = &max1619_driver;
224        new_client->flags = 0;
225
226        /*
227         * Now we do the remaining detection. A negative kind means that
228         * the driver was loaded with no force parameter (default), so we
229         * must both detect and identify the chip. A zero kind means that
230         * the driver was loaded with the force parameter, the detection
231         * step shall be skipped. A positive kind means that the driver
232         * was loaded with the force parameter and a given kind of chip is
233         * requested, so both the detection and the identification steps
234         * are skipped.
235         */
236
237        if (kind < 0) {
238                u8 reg_config, reg_convrate, reg_status;
239
240                reg_config = i2c_smbus_read_byte_data(new_client,
241                        MAX1619_REG_R_CONFIG);
242                reg_convrate = i2c_smbus_read_byte_data(new_client,
243                        MAX1619_REG_R_CONVRATE);
244                reg_status = i2c_smbus_read_byte_data(new_client,
245                        MAX1619_REG_R_STATUS);
246
247                if ((reg_config & 0x03) != 0x00
248                 || reg_convrate > 0x07
249                 || (reg_status & 0x61) != 0x00) {
250#ifdef DEBUG
251                        printk(KERN_DEBUG "max1619.o: Detection failed at "
252                               "0x%02x.\n", address);
253#endif
254                        goto ERROR1;
255                }
256        }
257
258        if (kind <= 0) {
259                u8 man_id, chip_id;
260
261                man_id = i2c_smbus_read_byte_data(new_client,
262                        MAX1619_REG_R_MAN_ID);
263                chip_id = i2c_smbus_read_byte_data(new_client,
264                        MAX1619_REG_R_CHIP_ID);
265
266                if ((man_id == 0x4D) && (chip_id == 0x04)) {
267                        kind = max1619;
268                }
269        }
270
271        if (kind <= 0) {
272                printk(KERN_INFO "max1619.o: Unsupported chip.\n");
273                goto ERROR1;
274        }
275
276        if (kind == max1619) {
277                type_name = "max1619";
278                client_name = "MAX1619 chip";
279        } else {
280                printk(KERN_ERR "max1619.o: Unknown kind %d.\n", kind);
281                goto ERROR1;
282        }
283
284        /*
285         * OK, we got a valid chip so we can fill in the remaining client
286         * fields.
287         */
288
289        strcpy(new_client->name, client_name);
290        new_client->id = max1619_id++;
291        data->valid = 0;
292        init_MUTEX(&data->update_lock);
293
294        /*
295         * Tell the I2C layer a new client has arrived.
296         */
297
298        if ((err = i2c_attach_client(new_client))) {
299                printk(KERN_ERR "max1619.o: Failed attaching client.\n");
300                goto ERROR1;
301        }
302
303        /*
304         * Register a new directory entry.
305         */
306
307        if ((err = i2c_register_entry(new_client, type_name,
308             max1619_dir_table_template, THIS_MODULE)) < 0) {
309                printk(KERN_ERR "max1619.o: Failed registering directory "
310                       "entry.\n");
311                goto ERROR2;
312        }
313        data->sysctl_id = err;
314
315        /*
316         * Initialize the MAX1619 chip.
317         */
318
319        max1619_init_client(new_client);
320        return 0;
321
322ERROR2:
323        i2c_detach_client(new_client);
324ERROR1:
325        kfree(data);
326        return err;
327}
328
329static void max1619_init_client(struct i2c_client *client)
330{
331        u8 config;
332
333        /*
334         * Start the conversions.
335         */
336
337        /* Set conversion rate to 2 Hz */
338        i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONVRATE, 5);
339
340        /* Start monitoring */
341        config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG);
342        if (config & 0x40)
343                i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONFIG,
344                        config & 0xBF);
345}
346
347
348static int max1619_detach_client(struct i2c_client *client)
349{
350        int err;
351
352        i2c_deregister_entry(((struct max1619_data *)
353                (client->data))->sysctl_id);
354        if ((err = i2c_detach_client(client))) {
355                printk(KERN_ERR "max1619.o: Client deregistration failed, "
356                       "client not detached.\n");
357                return err;
358        }
359
360        kfree(client->data);
361        return 0;
362}
363
364static void max1619_update_client(struct i2c_client *client)
365{
366        struct max1619_data *data = client->data;
367
368        down(&data->update_lock);
369
370        if ((jiffies - data->last_updated > HZ * 2) ||
371            (jiffies < data->last_updated) || !data->valid) {
372#ifdef DEBUG
373                printk(KERN_DEBUG "max1619.o: Updating data.\n");
374#endif
375
376                data->local_temp = i2c_smbus_read_byte_data(client,
377                        MAX1619_REG_R_LOCAL_TEMP);
378                data->remote_temp = i2c_smbus_read_byte_data(client,
379                        MAX1619_REG_R_REMOTE_TEMP);
380                data->remote_high = i2c_smbus_read_byte_data(client,
381                        MAX1619_REG_R_REMOTE_THIGH);
382                data->remote_low = i2c_smbus_read_byte_data(client,
383                        MAX1619_REG_R_REMOTE_TLOW);
384                data->remote_max = i2c_smbus_read_byte_data(client,
385                        MAX1619_REG_R_REMOTE_TMAX);
386                data->remote_hyst = i2c_smbus_read_byte_data(client,
387                        MAX1619_REG_R_REMOTE_THYST);
388                data->alarms = i2c_smbus_read_byte_data(client,
389                        MAX1619_REG_R_STATUS);
390
391                data->last_updated = jiffies;
392                data->valid = 1;
393        }
394
395        up(&data->update_lock);
396}
397
398static void max1619_local_temp(struct i2c_client *client, int operation,
399        int ctl_name, int *nrels_mag, long *results)
400{
401        struct max1619_data *data = client->data;
402
403        if (operation == SENSORS_PROC_REAL_INFO)
404                *nrels_mag = 0; /* magnitude */
405        else if (operation == SENSORS_PROC_REAL_READ) {
406                max1619_update_client(client);
407                results[0] = TEMP_FROM_REG(data->local_temp);
408                *nrels_mag = 1;
409        }
410
411}
412
413static void max1619_remote_temp(struct i2c_client *client, int operation,
414        int ctl_name, int *nrels_mag, long *results)
415{
416        struct max1619_data *data = client->data;
417
418        if (operation == SENSORS_PROC_REAL_INFO)
419                *nrels_mag = 0; /* magnitude */
420        else if (operation == SENSORS_PROC_REAL_READ) {
421                max1619_update_client(client);
422                results[0] = TEMP_FROM_REG(data->remote_high);
423                results[1] = TEMP_FROM_REG(data->remote_low);
424                results[2] = TEMP_FROM_REG(data->remote_temp);
425                *nrels_mag = 3;
426        } else if (operation == SENSORS_PROC_REAL_WRITE) {
427                if (*nrels_mag >= 1) {
428                        data->remote_high = TEMP_TO_REG(results[0]);
429                        i2c_smbus_write_byte_data(client,
430                                MAX1619_REG_W_REMOTE_THIGH, data->remote_high);
431                }
432                if (*nrels_mag >= 2) {
433                        data->remote_low = TEMP_TO_REG(results[1]);
434                        i2c_smbus_write_byte_data(client,
435                                MAX1619_REG_W_REMOTE_TLOW, data->remote_low);
436
437                }
438        }
439}
440
441static void max1619_remote_crit(struct i2c_client *client, int operation,
442        int ctl_name, int *nrels_mag, long *results)
443{
444        struct max1619_data *data = client->data;
445
446        if (operation == SENSORS_PROC_REAL_INFO)
447                *nrels_mag = 0; /* magnitude */
448        else if (operation == SENSORS_PROC_REAL_READ) {
449                max1619_update_client(client);
450                results[0] = TEMP_FROM_REG(data->remote_max);
451                results[1] = TEMP_FROM_REG(data->remote_hyst);
452                *nrels_mag = 2;
453        } else if (operation == SENSORS_PROC_REAL_WRITE) {
454                if (*nrels_mag >= 1) {
455                        data->remote_max = TEMP_TO_REG(results[0]);
456                        i2c_smbus_write_byte_data(client,
457                                MAX1619_REG_W_REMOTE_TMAX, data->remote_max);
458                }
459                if (*nrels_mag >= 2) {
460                        data->remote_hyst = TEMP_TO_REG(results[1]);
461                        i2c_smbus_write_byte_data(client,
462                                MAX1619_REG_W_REMOTE_THYST, data->remote_hyst);
463                }
464        }
465}
466
467static void max1619_alarms(struct i2c_client *client, int operation,
468        int ctl_name, int *nrels_mag, long *results)
469{
470        struct max1619_data *data = client->data;
471
472        if (operation == SENSORS_PROC_REAL_INFO)
473                *nrels_mag = 0; /* magnitude */
474        else if (operation == SENSORS_PROC_REAL_READ) {
475                max1619_update_client(client);
476                results[0] = data->alarms;
477                *nrels_mag = 1;
478        }
479}
480
481
482static int __init sm_max1619_init(void)
483{
484        printk(KERN_INFO "max1619.o version %s (%s)\n", LM_VERSION, LM_DATE);
485        return i2c_add_driver(&max1619_driver);
486}
487
488static void __exit sm_max1619_exit(void)
489{
490        i2c_del_driver(&max1619_driver);
491}
492
493MODULE_AUTHOR("Alexey Fisher <fishor@mail.ru>");
494MODULE_DESCRIPTION("MAX1619 sensor driver");
495MODULE_LICENSE("GPL");
496
497module_init(sm_max1619_init);
498module_exit(sm_max1619_exit);
Note: See TracBrowser for help on using the browser.