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

Revision 2867, 9.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    lm75.c - Part of lm_sensors, Linux kernel modules for hardware
3             monitoring
4    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.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#include <linux/module.h>
22#include <linux/slab.h>
23#include <linux/i2c.h>
24#include <linux/i2c-proc.h>
25#include <linux/init.h>
26#include "version.h"
27#include "lm75.h"
28
29/* Addresses to scan */
30static unsigned short normal_i2c[] = { SENSORS_I2C_END };
31static unsigned short normal_i2c_range[] = { 0x48, 0x4f, SENSORS_I2C_END };
32static unsigned int normal_isa[] = { SENSORS_ISA_END };
33static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
34
35/* Insmod parameters */
36SENSORS_INSMOD_1(lm75);
37
38/* Many LM75 constants specified below */
39
40/* The LM75 registers */
41#define LM75_REG_TEMP 0x00
42#define LM75_REG_CONF 0x01
43#define LM75_REG_TEMP_HYST 0x02
44#define LM75_REG_TEMP_OS 0x03
45
46/* Each client has this additional data */
47struct lm75_data {
48        struct i2c_client client;
49        int sysctl_id;
50
51        struct semaphore update_lock;
52        char valid;             /* !=0 if following fields are valid */
53        unsigned long last_updated;     /* In jiffies */
54
55        u16 temp, temp_os, temp_hyst;   /* Register values */
56};
57
58static int lm75_attach_adapter(struct i2c_adapter *adapter);
59static int lm75_detect(struct i2c_adapter *adapter, int address,
60                       unsigned short flags, int kind);
61static void lm75_init_client(struct i2c_client *client);
62static int lm75_detach_client(struct i2c_client *client);
63
64static int lm75_read_value(struct i2c_client *client, u8 reg);
65static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value);
66static void lm75_temp(struct i2c_client *client, int operation,
67                      int ctl_name, int *nrels_mag, long *results);
68static void lm75_update_client(struct i2c_client *client);
69
70
71/* This is the driver that will be inserted */
72static struct i2c_driver lm75_driver = {
73        .name           = "LM75 sensor chip driver",
74        .id             = I2C_DRIVERID_LM75,
75        .flags          = I2C_DF_NOTIFY,
76        .attach_adapter = lm75_attach_adapter,
77        .detach_client  = lm75_detach_client,
78};
79
80/* -- SENSORS SYSCTL START -- */
81
82#define LM75_SYSCTL_TEMP 1200   /* Degrees Celcius * 10 */
83
84/* -- SENSORS SYSCTL END -- */
85
86/* These files are created for each detected LM75. This is just a template;
87   though at first sight, you might think we could use a statically
88   allocated list, we need some way to get back to the parent - which
89   is done through one of the 'extra' fields which are initialized
90   when a new copy is allocated. */
91static ctl_table lm75_dir_table_template[] = {
92        {LM75_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real,
93         &i2c_sysctl_real, NULL, &lm75_temp},
94        {0}
95};
96
97static int lm75_attach_adapter(struct i2c_adapter *adapter)
98{
99        return i2c_detect(adapter, &addr_data, lm75_detect);
100}
101
102/* This function is called by i2c_detect */
103int lm75_detect(struct i2c_adapter *adapter, int address,
104                unsigned short flags, int kind)
105{
106        int i;
107        struct i2c_client *new_client;
108        struct lm75_data *data;
109        int err = 0;
110        const char *type_name, *client_name;
111
112        /* Make sure we aren't probing the ISA bus!! This is just a safety check
113           at this moment; i2c_detect really won't call us. */
114#ifdef DEBUG
115        if (i2c_is_isa_adapter(adapter)) {
116                printk
117                    ("lm75.o: lm75_detect called for an ISA bus adapter?!?\n");
118                return 0;
119        }
120#endif
121
122        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
123                                     I2C_FUNC_SMBUS_WORD_DATA))
124                    goto error0;
125
126        /* OK. For now, we presume we have a valid client. We now create the
127           client structure, even though we cannot fill it completely yet.
128           But it allows us to access lm75_{read,write}_value. */
129        if (!(data = kmalloc(sizeof(struct lm75_data), GFP_KERNEL))) {
130                err = -ENOMEM;
131                goto error0;
132        }
133
134        new_client = &data->client;
135        new_client->addr = address;
136        new_client->data = data;
137        new_client->adapter = adapter;
138        new_client->driver = &lm75_driver;
139        new_client->flags = 0;
140
141        /* Now, we do the remaining detection. There is no identification-
142           dedicated register so we have to rely on several tricks:
143           unused bits, registers cycling over 8-address boundaries,
144           addresses 0x04-0x07 returning the last read value.
145           The cycling+unused addresses combination is not tested,
146           since it would significantly slow the detection down and would
147           hardly add any value. */
148        if (kind < 0) {
149                int cur, conf, hyst, os;
150
151                /* Unused addresses */
152                cur = i2c_smbus_read_word_data(new_client, 0);
153                conf = i2c_smbus_read_byte_data(new_client, 1);
154                hyst = i2c_smbus_read_word_data(new_client, 2);
155                if (i2c_smbus_read_word_data(new_client, 4) != hyst
156                 || i2c_smbus_read_word_data(new_client, 5) != hyst
157                 || i2c_smbus_read_word_data(new_client, 6) != hyst
158                 || i2c_smbus_read_word_data(new_client, 7) != hyst)
159                        goto error1;
160                os = i2c_smbus_read_word_data(new_client, 3);
161                if (i2c_smbus_read_word_data(new_client, 4) != os
162                 || i2c_smbus_read_word_data(new_client, 5) != os
163                 || i2c_smbus_read_word_data(new_client, 6) != os
164                 || i2c_smbus_read_word_data(new_client, 7) != os)
165                        goto error1;
166
167                /* Unused bits */
168                if (conf & 0xe0)
169                        goto error1;
170
171                /* Addresses cycling */
172                for (i = 8; i < 0xff; i += 8)
173                        if (i2c_smbus_read_byte_data(new_client, i + 1) != conf
174                         || i2c_smbus_read_word_data(new_client, i + 2) != hyst
175                         || i2c_smbus_read_word_data(new_client, i + 3) != os)
176                                goto error1;
177        }
178
179        /* Determine the chip type - only one kind supported! */
180        if (kind <= 0)
181                kind = lm75;
182
183        if (kind == lm75) {
184                type_name = "lm75";
185                client_name = "LM75 chip";
186        } else {
187                pr_debug("lm75.o: Internal error: unknown kind (%d)?!?", kind);
188                goto error1;
189        }
190
191        /* Fill in the remaining client fields and put it into the global list */
192        strcpy(new_client->name, client_name);
193        data->valid = 0;
194        init_MUTEX(&data->update_lock);
195
196        /* Tell the I2C layer a new client has arrived */
197        if ((err = i2c_attach_client(new_client)))
198                goto error3;
199
200        /* Register a new directory entry with module sensors */
201        if ((i = i2c_register_entry(new_client, type_name,
202                                        lm75_dir_table_template,
203                                        THIS_MODULE)) < 0) {
204                err = i;
205                goto error4;
206        }
207        data->sysctl_id = i;
208
209        lm75_init_client(new_client);
210        return 0;
211
212/* OK, this is not exactly good programming practice, usually. But it is
213   very code-efficient in this case. */
214
215      error4:
216        i2c_detach_client(new_client);
217      error3:
218      error1:
219        kfree(data);
220      error0:
221        return err;
222}
223
224static int lm75_detach_client(struct i2c_client *client)
225{
226        struct lm75_data *data = client->data;
227
228        i2c_deregister_entry(data->sysctl_id);
229        i2c_detach_client(client);
230        kfree(client->data);
231        return 0;
232}
233
234/* All registers are word-sized, except for the configuration register.
235   LM75 uses a high-byte first convention, which is exactly opposite to
236   the usual practice. */
237static int lm75_read_value(struct i2c_client *client, u8 reg)
238{
239        if (reg == LM75_REG_CONF)
240                return i2c_smbus_read_byte_data(client, reg);
241        else
242                return swab16(i2c_smbus_read_word_data(client, reg));
243}
244
245/* All registers are word-sized, except for the configuration register.
246   LM75 uses a high-byte first convention, which is exactly opposite to
247   the usual practice. */
248static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value)
249{
250        if (reg == LM75_REG_CONF)
251                return i2c_smbus_write_byte_data(client, reg, value);
252        else
253                return i2c_smbus_write_word_data(client, reg, swab16(value));
254}
255
256static void lm75_init_client(struct i2c_client *client)
257{
258        /* Initialize the LM75 chip */
259        lm75_write_value(client, LM75_REG_CONF, 0);
260}
261
262static void lm75_update_client(struct i2c_client *client)
263{
264        struct lm75_data *data = client->data;
265
266        down(&data->update_lock);
267
268        if ((jiffies - data->last_updated > HZ + HZ / 2) ||
269            (jiffies < data->last_updated) || !data->valid) {
270                pr_debug("Starting lm75 update\n");
271
272                data->temp = lm75_read_value(client, LM75_REG_TEMP);
273                data->temp_os = lm75_read_value(client, LM75_REG_TEMP_OS);
274                data->temp_hyst =
275                    lm75_read_value(client, LM75_REG_TEMP_HYST);
276                data->last_updated = jiffies;
277                data->valid = 1;
278        }
279
280        up(&data->update_lock);
281}
282
283
284void lm75_temp(struct i2c_client *client, int operation, int ctl_name,
285               int *nrels_mag, long *results)
286{
287        struct lm75_data *data = client->data;
288        if (operation == SENSORS_PROC_REAL_INFO)
289                *nrels_mag = 1;
290        else if (operation == SENSORS_PROC_REAL_READ) {
291                lm75_update_client(client);
292                results[0] = LM75_TEMP_FROM_REG(data->temp_os);
293                results[1] = LM75_TEMP_FROM_REG(data->temp_hyst);
294                results[2] = LM75_TEMP_FROM_REG(data->temp);
295                *nrels_mag = 3;
296        } else if (operation == SENSORS_PROC_REAL_WRITE) {
297                if (*nrels_mag >= 1) {
298                        data->temp_os = LM75_TEMP_TO_REG(results[0]);
299                        lm75_write_value(client, LM75_REG_TEMP_OS,
300                                         data->temp_os);
301                }
302                if (*nrels_mag >= 2) {
303                        data->temp_hyst = LM75_TEMP_TO_REG(results[1]);
304                        lm75_write_value(client, LM75_REG_TEMP_HYST,
305                                         data->temp_hyst);
306                }
307        }
308}
309
310static int __init sm_lm75_init(void)
311{
312        printk(KERN_INFO "lm75.o version %s (%s)\n", LM_VERSION, LM_DATE);
313        return i2c_add_driver(&lm75_driver);
314}
315
316static void __exit sm_lm75_exit(void)
317{
318        i2c_del_driver(&lm75_driver);
319}
320
321MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
322MODULE_DESCRIPTION("LM75 driver");
323MODULE_LICENSE("GPL");
324
325module_init(sm_lm75_init);
326module_exit(sm_lm75_exit);
Note: See TracBrowser for help on using the browser.