root/lm-sensors/trunk/kernel/chips/w83l785ts.c @ 2781

Revision 2781, 9.9 KB (checked in by khali, 8 years ago)

Discard owner field from i2c_driver structure. I do not restore
inc_use/dec_use because they are not actually used anywhere.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * w83l785ts.c - Part of lm_sensors, Linux kernel modules for hardware
3 *               monitoring
4 * Copyright (C) 2003-2004  Jean Delvare <khali@linux-fr.org>
5 *
6 * Inspired from the lm83 driver. The W83L785TS-S is a sensor chip made
7 * by Winbond. It reports a single external temperature with a 1 deg
8 * resolution and a 3 deg accuracy. Data sheet can be obtained from
9 * Winbond's website at:
10 *   http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf
11 *
12 * Thanks to James Bolt <james@evilpenguin.com> for benchmarking the read
13 * error handling mechanism.
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 <linux/delay.h>
36#include "version.h"
37
38#ifndef I2C_DRIVERID_W83L785TS
39#define I2C_DRIVERID_W83L785TS  1047
40#endif
41
42/* How many retries on register read error */
43#define MAX_RETRIES     5
44
45/*
46 * Address to scan
47 * Address is fully defined internally and cannot be changed.
48 */
49
50static unsigned short normal_i2c[] = { 0x2e, SENSORS_I2C_END };
51static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
52static unsigned int normal_isa[] = { SENSORS_ISA_END };
53static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
54
55/*
56 * Insmod parameters
57 */
58
59SENSORS_INSMOD_1(w83l785ts);
60
61/*
62 * The W83L785TS-S registers
63 * Manufacturer ID is 0x5CA3 for Winbond.
64 */
65
66#define W83L785TS_REG_MAN_ID1           0x4D
67#define W83L785TS_REG_MAN_ID2           0x4C
68#define W83L785TS_REG_CHIP_ID           0x4E
69#define W83L785TS_REG_CONFIG            0x40
70#define W83L785TS_REG_TYPE              0x52
71#define W83L785TS_REG_TEMP              0x27
72#define W83L785TS_REG_TEMP_OVER         0x53 /* not sure about this one */
73
74/*
75 * Conversions
76 * The W83L785TS-S uses signed 8-bit values.
77 */
78
79#define TEMP_FROM_REG(val)      (val & 0x80 ? val-0x100 : val)
80
81/*
82 * Functions declaration
83 */
84
85static int w83l785ts_attach_adapter(struct i2c_adapter *adapter);
86static int w83l785ts_detect(struct i2c_adapter *adapter, int address, unsigned
87        short flags, int kind);
88static int w83l785ts_detach_client(struct i2c_client *client);
89static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval);
90static void w83l785ts_update_client(struct i2c_client *client);
91static void w83l785ts_temp(struct i2c_client *client, int operation, int
92        ctl_name, int *nrels_mag, long *results);
93
94/*
95 * Driver data (common to all clients)
96 */
97 
98static struct i2c_driver w83l785ts_driver = {
99        .name           = "W83L785S-S sensor driver",
100        .id             = I2C_DRIVERID_W83L785TS,
101        .flags          = I2C_DF_NOTIFY,
102        .attach_adapter = w83l785ts_attach_adapter,
103        .detach_client  = w83l785ts_detach_client,
104};
105
106/*
107 * Client data (each client gets its own)
108 */
109
110struct w83l785ts_data {
111        struct i2c_client client;
112        int sysctl_id;
113
114        struct semaphore update_lock;
115        char valid; /* zero until following fields are valid */
116        unsigned long last_updated; /* in jiffies */
117
118        /* registers values */
119        u8 temp, temp_over;
120};
121
122/*
123 * Proc entries
124 * These files are created for each detected W83L785TS-S.
125 */
126
127/* -- SENSORS SYSCTL START -- */
128
129#define W83L785TS_SYSCTL_TEMP   1200
130
131/* -- SENSORS SYSCTL END -- */
132
133
134static ctl_table w83l785ts_dir_table_template[] =
135{
136        {W83L785TS_SYSCTL_TEMP, "temp", NULL, 0, 0444, NULL,
137         &i2c_proc_real, &i2c_sysctl_real, NULL, &w83l785ts_temp},
138        {0}
139};
140
141/*
142 * Internal variables
143 */
144
145static int w83l785ts_id = 0;
146
147/*
148 * Real code
149 */
150
151static int w83l785ts_attach_adapter(struct i2c_adapter *adapter)
152{
153        return i2c_detect(adapter, &addr_data, w83l785ts_detect);
154}
155
156/*
157 * The following function does more than just detection. If detection
158 * succeeds, it also registers the new chip.
159 */
160static int w83l785ts_detect(struct i2c_adapter *adapter, int address,
161        unsigned short flags, int kind)
162{
163        struct i2c_client *new_client;
164        struct w83l785ts_data *data;
165        int err = 0;
166        const char *type_name = "";
167        const char *client_name = "";
168
169        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
170#ifdef DEBUG
171                printk(KERN_DEBUG "w83l785ts.o: I2C bus doesn't support "
172                        "byte read mode, skipping.\n");
173#endif
174                return 0;
175        }
176
177        if (!(data = kmalloc(sizeof(struct w83l785ts_data), GFP_KERNEL))) {
178                printk(KERN_ERR "w83l785ts.o: Out of memory in w83l785ts_detect "
179                        "(new_client).\n");
180                return -ENOMEM;
181        }
182
183        /*
184         * The common I2C client data is placed right after the
185         * W83L785TS-specific. The W83L785TS-specific data is pointed to by the
186         * data field from the I2C client data.
187         */
188
189        new_client = &data->client;
190        new_client->addr = address;
191        new_client->data = data;
192        new_client->adapter = adapter;
193        new_client->driver = &w83l785ts_driver;
194        new_client->flags = 0;
195
196        /*
197         * Now we do the remaining detection. A negative kind means that
198         * the driver was loaded with no force parameter (default), so we
199         * must both detect and identify the chip (actually there is only
200         * one possible kind of chip for now, W83L785TS-S). A zero kind means
201         * that the driver was loaded with the force parameter, the detection
202         * step shall be skipped. A positive kind means that the driver
203         * was loaded with the force parameter and a given kind of chip is
204         * requested, so both the detection and the identification steps
205         * are skipped.
206         */
207
208        if (kind < 0) { /* detection */
209                if (((w83l785ts_read_value(new_client, W83L785TS_REG_CONFIG, 0)
210                        & 0x80) != 0x00)
211                 || ((w83l785ts_read_value(new_client, W83L785TS_REG_TYPE, 0)
212                        & 0xFC) != 0x00)) {
213#ifdef DEBUG
214                        printk(KERN_DEBUG "w83l785ts.o: Detection failed at "
215                                "0x%02x.\n", address);
216#endif
217                        goto ERROR1;
218                }
219        }
220
221        if (kind <= 0) { /* identification */
222                u16 man_id;
223                u8 chip_id;
224
225                man_id = (w83l785ts_read_value(new_client, W83L785TS_REG_MAN_ID1, 0) << 8)
226                       +  w83l785ts_read_value(new_client, W83L785TS_REG_MAN_ID2, 0);
227                chip_id = w83l785ts_read_value(new_client, W83L785TS_REG_CHIP_ID, 0);
228                if (man_id == 0x5CA3) { /* Winbond */
229                        if (chip_id == 0x70)
230                                kind = w83l785ts;
231                }
232        }
233
234        if (kind <= 0) { /* identification failed */
235                printk(KERN_INFO "w83l785ts.o: Unsupported chip.\n");
236                goto ERROR1;
237        }
238
239        if (kind == w83l785ts) {
240                type_name = "w83l785ts";
241                client_name = "W83L785TS-S chip";
242        } else {
243                printk(KERN_ERR "w83l785ts.o: Unknown kind %d.\n", kind);
244                goto ERROR1;
245        }
246       
247        /*
248         * OK, we got a valid chip so we can fill in the remaining client
249         * fields.
250         */
251
252        strcpy(new_client->name, client_name);
253        new_client->id = w83l785ts_id++;
254        data->valid = 0;
255        init_MUTEX(&data->update_lock);
256
257        /*
258         * Tell the I2C layer a new client has arrived.
259         */
260
261        if ((err = i2c_attach_client(new_client))) {
262#ifdef DEBUG
263                printk(KERN_ERR "w83l785ts.o: Failed attaching client.\n");
264#endif
265                goto ERROR1;
266        }
267
268        /*
269         * Register a new directory entry.
270         */
271
272        if ((err = i2c_register_entry(new_client, type_name,
273            w83l785ts_dir_table_template)) < 0) {
274#ifdef DEBUG
275                printk(KERN_ERR "w83l785ts.o: Failed registering directory "
276                        "entry.\n");
277#endif
278                goto ERROR2;
279        }
280        data->sysctl_id = err;
281
282        /*
283         * Initialize the W83L785TS chip
284         * Nothing yet, assume it is already started.
285         */
286
287        return 0;
288
289        ERROR2:
290        i2c_detach_client(new_client);
291        ERROR1:
292        kfree(data);
293        return err;
294}
295
296static int w83l785ts_detach_client(struct i2c_client *client)
297{
298        int err;
299
300        i2c_deregister_entry(((struct w83l785ts_data *) (client->data))->sysctl_id);
301        if ((err = i2c_detach_client(client))) {
302                printk(KERN_ERR "w83l785ts.o: Client deregistration failed, "
303                        "client not detached.\n");
304                return err;
305        }
306
307        kfree(client->data);
308        return 0;
309}
310
311static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval)
312{
313        int value, i;
314
315        /* Frequent read errors have been reported on Asus boards, so we
316         * retry on read errors. If it still fails (unlikely), return the
317         * default value requested by the caller. */
318        for (i = 1; i <= MAX_RETRIES; i++) {
319                value = i2c_smbus_read_byte_data(client, reg);
320                if (value >= 0)
321                        return value;
322                printk(KERN_WARNING "w83l785ts.o: Read failed, will retry "
323                        "in %d.\n", i);
324                mdelay(i);
325        }
326
327        printk(KERN_ERR "w83l785ts.o: Couldn't read value from register. "
328                "Please report.\n");
329        return defval;
330}
331
332static void w83l785ts_update_client(struct i2c_client *client)
333{
334        struct w83l785ts_data *data = client->data;
335
336        down(&data->update_lock);
337
338        if ((jiffies - data->last_updated > HZ * 2)
339         || (jiffies < data->last_updated)
340         || !data->valid) {
341#ifdef DEBUG
342                printk(KERN_DEBUG "w83l785ts.o: Updating data.\n");
343#endif
344                data->temp = w83l785ts_read_value(client, W83L785TS_REG_TEMP,
345                        data->temp);
346                data->temp_over = w83l785ts_read_value(client,
347                        W83L785TS_REG_TEMP_OVER, data->temp_over);
348                data->last_updated = jiffies;
349                data->valid = 1;
350        }
351
352        up(&data->update_lock);
353}
354
355static void w83l785ts_temp(struct i2c_client *client, int operation,
356        int ctl_name, int *nrels_mag, long *results)
357{
358        struct w83l785ts_data *data = client->data;
359
360        if (operation == SENSORS_PROC_REAL_INFO) {
361                *nrels_mag = 0; /* magnitude */
362        } else if (operation == SENSORS_PROC_REAL_READ) {
363                w83l785ts_update_client(client);
364                results[0] = TEMP_FROM_REG(data->temp_over);
365                results[1] = TEMP_FROM_REG(data->temp);
366                *nrels_mag = 2;
367        }
368}
369
370static int __init sm_w83l785ts_init(void)
371{
372        printk(KERN_INFO "w83l785ts.o version %s (%s)\n", LM_VERSION, LM_DATE);
373        return i2c_add_driver(&w83l785ts_driver);
374}
375
376static void __exit sm_w83l785ts_exit(void)
377{
378        i2c_del_driver(&w83l785ts_driver);
379}
380
381MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
382MODULE_DESCRIPTION("W83L785TS-S sensor driver");
383MODULE_LICENSE("GPL");
384
385module_init(sm_w83l785ts_init);
386module_exit(sm_w83l785ts_exit);
Note: See TracBrowser for help on using the browser.