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

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