root/lm-sensors/trunk/kernel/chips/saa1064.c @ 2445

Revision 2445, 13.4 KB (checked in by khali, 9 years ago)

Backport memory allocation reworking from Linux 2.6.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    saa1064.c - Part of lm_sensors, Linux kernel modules for hardware
3             monitoring
4    Copyright (c) 2003  Sascha Volkenandt <sascha@akv-soft.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/* A few notes about the SAA1064:
22
23* The SAA1064 is a driver for 4-digit led displays produced by Philips
24  Semiconductors. It can be found in HiFi equipment with such displays.
25  I've found it inside a Kathrein analogue sat-receiver :-).
26
27* The SAA1064 is quite simple to handle, it receives an address byte,
28  telling which register is addressed, followed by up to five data
29  bytes (according to the data sheet), while with each byte the register
30  address is increased by one, wrapping from 7 to 0.
31
32* NOTE: This device doesn NOT have eight read-write registers, but eight
33  write-only registers, and one read-only status byte (with no register
34  address).
35
36*/
37
38#include <linux/version.h>
39#include <linux/module.h>
40#include <linux/slab.h>
41#include <linux/i2c.h>
42#include <linux/i2c-proc.h>
43#include <linux/init.h>
44#include "version.h"
45
46MODULE_LICENSE("GPL");
47
48/* Addresses to scan */
49static unsigned short normal_i2c[] = { SENSORS_I2C_END };
50static unsigned short normal_i2c_range[] = { 0x38, 0x3b, SENSORS_I2C_END };
51static unsigned int normal_isa[] = { SENSORS_ISA_END };
52static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
53
54/* Insmod parameters */
55SENSORS_INSMOD_1(saa1064);
56
57/* The SAA1064 registers
58  Registers:
59  0 Control register
60  1 Digit 1
61  2 Digit 2
62  3 Digit 3
63  4 Digit 4
64*/
65
66#define SAA1064_REG_CONTROL 0x00
67#define SAA1064_REG_DIGIT0 0x01
68#define SAA1064_REG_DIGIT1 0x02
69#define SAA1064_REG_DIGIT2 0x03
70#define SAA1064_REG_DIGIT3 0x04
71
72/* Control byte:
73   Bit  0  Dynamic mode
74        1  Blank digits 1+3 (reversed)
75        2  Blank digits 2+4 (reversed)
76        3  Testmode (all digits on)
77        4  Add 3mA output current to led's
78        5  Add 6mA output current to led's
79        6  Add 12mA output current to led's
80        7  Unused, set to 0
81*/
82
83#define SAA1064_CTRL_DYNAMIC 0x01
84#define SAA1064_CTRL_BLANK13 0x02
85#define SAA1064_CTRL_BLANK24 0x04
86#define SAA1064_CTRL_TEST    0x08
87#define SAA1064_CTRL_BRIGHT  0x70
88
89/* Status byte:
90   The MSB set to 1 indicates powerloss since last read-out */
91#define SAA1064_STAT_PWRLOSS 0x80
92
93/* Get a bit from the control-byte. Except for BRIGHT, these return
94   zero/non-zero in a boolean fashion. BRIGHT returns a 3-bit value
95   specifying the brightness */
96#define SAA1064_CTRL_GET_DYNAMIC(c) (((c) & SAA1064_CTRL_DYNAMIC)>0)
97#define SAA1064_CTRL_GET_BLANK13(c) (((c) & SAA1064_CTRL_BLANK13)>0)
98#define SAA1064_CTRL_GET_BLANK24(c) (((c) & SAA1064_CTRL_BLANK24)>0)
99#define SAA1064_CTRL_GET_TEST(c)    (((c) & SAA1064_CTRL_TEST)>0)
100#define SAA1064_CTRL_GET_BRIGHT(c)  (((c) & SAA1064_CTRL_BRIGHT)>>4)
101
102/* Get THE bit from the status byte. The LSB set to 1 indicates powerloss
103   since last read-out */
104#define SAA1064_STAT_GET_PWRLOSS(s)  (((s) & SAA1064_STAT_PWRLOSS)>0)
105
106/* Set a bit in the control-byte to val and return the modified byte.
107   Except for BRIGHT, val is evaluated in a boolean fashion. */
108#define SAA1064_CTRL_SET_DYNAMIC(c,val) ((val)>0 \
109        ? (c) | SAA1064_CTRL_DYNAMIC : (c) & ~SAA1064_CTRL_DYNAMIC)
110#define SAA1064_CTRL_SET_BLANK13(c,val) ((val)>0 \
111        ? (c) | SAA1064_CTRL_BLANK13 : (c) & ~SAA1064_CTRL_BLANK13)
112#define SAA1064_CTRL_SET_BLANK24(c,val) ((val)>0 \
113        ? (c) | SAA1064_CTRL_BLANK24 : (c) & ~SAA1064_CTRL_BLANK24)
114#define SAA1064_CTRL_SET_TEST(c,val) ((val)>0 \
115        ? (c) | SAA1064_CTRL_TEST : (c) & ~SAA1064_CTRL_TEST)
116#define SAA1064_CTRL_SET_BRIGHT(c,val) (((c) & ~SAA1064_CTRL_BRIGHT) \
117        | (((val) << 4) & SAA1064_CTRL_BRIGHT))
118
119/* Initial values */
120#define SAA1064_INIT 0x7f       /* All digits on (testmode), full brightness */
121
122/* Each client has this additional data */
123struct saa1064_data {
124        struct i2c_client client;
125        int sysctl_id;
126
127        struct semaphore update_lock;
128        char valid;   /* !=0 if following fields are valid */
129        unsigned long last_updated; /* In jiffies */
130
131        u8 control;             /* Control reg */
132        u8 digits[4];   /* Digits regs */
133        u8 status;    /* Status byte (read) */
134};
135
136static int saa1064_attach_adapter(struct i2c_adapter *adapter);
137static int saa1064_detect(struct i2c_adapter *adapter, int address,
138                          unsigned short flags, int kind);
139static int saa1064_detach_client(struct i2c_client *client);
140
141static void saa1064_bright(struct i2c_client *client, int operation,
142                                       int ctl_name, int *nrels_mag, long *results);
143static void saa1064_test(struct i2c_client *client, int operation,
144                                       int ctl_name, int *nrels_mag, long *results);
145static void saa1064_disp(struct i2c_client *client, int operation,
146                                       int ctl_name, int *nrels_mag, long *results);
147static void saa1064_refresh(struct i2c_client *client, int operation,
148                                       int ctl_name, int *nrels_mag, long *results);
149static void saa1064_update_client(struct i2c_client *client);
150static void saa1064_init_client(struct i2c_client *client);
151
152/* This is the driver that will be inserted */
153static struct i2c_driver saa1064_driver = {
154        .owner          = THIS_MODULE,
155        .name           = "SAA1064 sensor chip driver",
156        .id             = I2C_DRIVERID_SAA1064,
157        .flags          = I2C_DF_NOTIFY,
158        .attach_adapter = saa1064_attach_adapter,
159        .detach_client  = saa1064_detach_client,
160};
161
162/* -- SENSORS SYSCTL START -- */
163
164#define SAA1064_SYSCTL_BRIGHT     1000 /* Brightness, 0-7 */
165#define SAA1064_SYSCTL_TEST       1001 /* Testmode (on = all digits lit) */
166#define SAA1064_SYSCTL_DISP       1005 /* four eight bit values */
167#define SAA1064_SYSCTL_REFRESH    1006 /* refresh digits in case of powerloss */
168
169/* -- SENSORS SYSCTL END -- */
170
171/* These files are created for each detected SAA1064. This is just a template;
172   though at first sight, you might think we could use a statically
173   allocated list, we need some way to get back to the parent - which
174   is done through one of the 'extra' fields which are initialized
175   when a new copy is allocated. */
176static ctl_table saa1064_dir_table_template[] = {
177        {SAA1064_SYSCTL_BRIGHT, "bright", NULL, 0, 0644, NULL, &i2c_proc_real,
178         &i2c_sysctl_real, NULL, &saa1064_bright},
179        {SAA1064_SYSCTL_TEST, "test", NULL, 0, 0644, NULL, &i2c_proc_real,
180         &i2c_sysctl_real, NULL, &saa1064_test},
181        {SAA1064_SYSCTL_DISP, "disp", NULL, 0, 0644, NULL, &i2c_proc_real,
182         &i2c_sysctl_real, NULL, &saa1064_disp},
183        {SAA1064_SYSCTL_REFRESH, "refresh", NULL, 0, 0444, NULL, &i2c_proc_real,
184         &i2c_sysctl_real, NULL, &saa1064_refresh},
185        {0}
186};
187
188static int saa1064_id = 0;
189
190static int saa1064_attach_adapter(struct i2c_adapter *adapter)
191{
192        return i2c_detect(adapter, &addr_data, saa1064_detect);
193}
194
195/* This function is called by i2c_detect */
196static int saa1064_detect(struct i2c_adapter *adapter, int address,
197                   unsigned short flags, int kind)
198{
199        int i;
200        struct i2c_client *new_client;
201        struct saa1064_data *data;
202        int err = 0;
203        const char *type_name, *client_name;
204
205        /* Make sure we aren't probing the ISA bus!! This is just a safety check
206           at this moment; i2c_detect really won't call us. */
207#ifdef DEBUG
208        if (i2c_is_isa_adapter(adapter)) {
209                printk
210                    ("saa1064.o: saa1064_detect called for an ISA bus adapter?!?\n");
211                return 0;
212        }
213#endif
214
215        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE
216                        | I2C_FUNC_SMBUS_WRITE_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK))
217                goto ERROR0;
218
219        /* OK. For now, we presume we have a valid client. We now create the
220           client structure, even though we cannot fill it completely yet.
221           But it allows us to access i2c_smbus_read_byte */
222        if (!(data = kmalloc(sizeof(struct saa1064_data), GFP_KERNEL))) {
223                err = -ENOMEM;
224                goto ERROR0;
225        }
226
227        new_client = &data->client;
228        new_client->addr = address;
229        new_client->data = data;
230        new_client->adapter = adapter;
231        new_client->driver = &saa1064_driver;
232        new_client->flags = 0;
233
234        if (kind < 0) {
235                if ((i2c_smbus_read_byte(new_client) & ~SAA1064_STAT_PWRLOSS) != 0x00
236                                || i2c_smbus_read_byte(new_client) != 0x00
237                                || i2c_smbus_read_byte(new_client) != 0x00
238                                || i2c_smbus_read_byte(new_client) != 0x00)
239                        goto ERROR1;
240        }
241
242        /* If detection was requested, it has also passed til now. Only one chip,
243           so no further evaluation of kind. */
244        kind = saa1064;
245        type_name = "saa1064";
246        client_name = "SAA1064 chip";
247
248        /* Fill in the remaining client fields and put it into the global list */
249        strcpy(new_client->name, client_name);
250
251        new_client->id = saa1064_id++;
252        data->valid = 0;
253        init_MUTEX(&data->update_lock);
254
255        /* Tell the I2C layer a new client has arrived */
256        if ((err = i2c_attach_client(new_client)))
257                goto ERROR3;
258
259        /* Register a new directory entry with module sensors */
260        if ((i = i2c_register_entry(new_client, type_name,
261                                        saa1064_dir_table_template)) < 0) {
262                err = i;
263                goto ERROR4;
264        }
265        data->sysctl_id = i;
266
267#ifdef DEBUG
268        printk("saa1064.o: Module initialization complete.\n");
269#endif
270
271        /* Initialize the SAA1064 chip */
272        saa1064_init_client(new_client);
273        return 0;
274
275/* OK, this is not exactly good programming practice, usually. But it is
276   very code-efficient in this case. */
277
278      ERROR4:
279        i2c_detach_client(new_client);
280      ERROR3:
281      ERROR1:
282        kfree(data);
283      ERROR0:
284        return err;
285}
286
287
288int saa1064_detach_client(struct i2c_client *client)
289{
290        int err;
291
292        i2c_deregister_entry(((struct saa1064_data *) (client->data))->
293                                 sysctl_id);
294
295        if ((err = i2c_detach_client(client))) {
296                printk
297                    ("saa1064.o: Client deregistration failed, client not detached.\n");
298                return err;
299        }
300
301        kfree(client->data);
302
303        return 0;
304}
305
306/* Called when we have found a new SAA1064. */
307void saa1064_init_client(struct i2c_client *client)
308{
309        struct saa1064_data *data = client->data;
310        data->control = SAA1064_INIT;
311        memset(data->digits, 0x00, 4);
312
313        i2c_smbus_write_byte_data(client, SAA1064_REG_CONTROL, data->control);
314        i2c_smbus_write_i2c_block_data(client, SAA1064_REG_DIGIT0, 4, data->digits);
315}
316
317/* Update status byte, and write registers in case a powerloss occurred */
318static void saa1064_update_client(struct i2c_client *client)
319{
320        struct saa1064_data *data = client->data;
321
322        down(&data->update_lock);
323
324        if ((jiffies - data->last_updated > 5*HZ) ||
325            (jiffies < data->last_updated) || !data->valid) {
326
327#ifdef DEBUG
328                printk("saa1064.o: starting saa1064 update\n");
329#endif
330
331                data->status = i2c_smbus_read_byte(client);
332                if (SAA1064_STAT_GET_PWRLOSS(data->status)) {
333                        i2c_smbus_write_byte_data(client, SAA1064_REG_CONTROL, data->control);
334                        i2c_smbus_write_i2c_block_data(client, SAA1064_REG_DIGIT0, 4, data->digits);
335                }
336               
337                data->last_updated = jiffies;
338                data->valid = 1;
339        }
340
341        up(&data->update_lock);
342}
343
344
345static void saa1064_bright(struct i2c_client *client, int operation,
346                    int ctl_name, int *nrels_mag, long *results)
347{
348        struct saa1064_data *data = client->data;
349        if (operation == SENSORS_PROC_REAL_INFO)
350                *nrels_mag = 0;
351        else if (operation == SENSORS_PROC_REAL_READ) {
352                results[0] = SAA1064_CTRL_GET_BRIGHT(data->control);
353                *nrels_mag = 1;
354        } else if (operation == SENSORS_PROC_REAL_WRITE) {
355                if (*nrels_mag >= 1) {
356                        data->control = SAA1064_CTRL_SET_BRIGHT(data->control, results[0]);
357                        i2c_smbus_write_byte_data(client, SAA1064_REG_CONTROL, data->control);
358                }
359        }
360}
361
362
363static void saa1064_test(struct i2c_client *client, int operation,
364                    int ctl_name, int *nrels_mag, long *results)
365{
366        struct saa1064_data *data = client->data;
367        if (operation == SENSORS_PROC_REAL_INFO)
368                *nrels_mag = 0;
369        else if (operation == SENSORS_PROC_REAL_READ) {
370                results[0] = SAA1064_CTRL_GET_TEST(data->control);
371                *nrels_mag = 1;
372        } else if (operation == SENSORS_PROC_REAL_WRITE) {
373                if (*nrels_mag >= 1) {
374                        data->control = SAA1064_CTRL_SET_TEST(data->control, results[0]);
375                        i2c_smbus_write_byte_data(client, SAA1064_REG_CONTROL, data->control);
376                }
377        }
378}
379
380
381static void saa1064_disp(struct i2c_client *client, int operation,
382                    int ctl_name, int *nrels_mag, long *results)
383{
384        struct saa1064_data *data = client->data;
385        int i;
386
387        if (operation == SENSORS_PROC_REAL_INFO)
388                *nrels_mag = 0;
389        else if (operation == SENSORS_PROC_REAL_READ) {
390                for (i = 0; i < 4; ++i)
391                        results[i] = (long)data->digits[i];
392                *nrels_mag = 4;
393        } else if (operation == SENSORS_PROC_REAL_WRITE) {
394                for (i = 0; i < max(*nrels_mag, 4); ++i)
395                        data->digits[i] = (u8)results[i];
396                i2c_smbus_write_i2c_block_data(client, SAA1064_REG_DIGIT0, 4, data->digits);
397        }
398}
399
400
401static void saa1064_refresh(struct i2c_client *client, int operation,
402                    int ctl_name, int *nrels_mag, long *results)
403{
404        if (operation == SENSORS_PROC_REAL_INFO)
405                *nrels_mag = 0;
406        else if (operation == SENSORS_PROC_REAL_READ) {
407                saa1064_update_client(client);
408                *nrels_mag = 0;
409        } 
410}
411
412
413static int __init sensors_saa1064_init(void)
414{
415        printk("saa1064.o version %s (%s)\n", LM_VERSION, LM_DATE);
416        return i2c_add_driver(&saa1064_driver);
417}
418
419
420static void __exit sensors_saa1064_exit(void)
421{
422        i2c_del_driver(&saa1064_driver);
423}
424
425
426
427MODULE_AUTHOR("Sascha Volkenandt <sascha@akv-soft.de>");
428MODULE_DESCRIPTION("SAA1064 driver");
429
430module_init(sensors_saa1064_init);
431module_exit(sensors_saa1064_exit);
432
Note: See TracBrowser for help on using the browser.