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

Revision 2867, 7.6 KB (checked in by khali, 10 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    icspll.c - Part of lm_sensors, Linux kernel modules for hardware
3               monitoring
4    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>,
5    Philip Edelbrock <phil@netroedge.com>,
6    and Mark Studebaker <mdsxyz123@yahoo.com>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22
23/*
24    ** WARNING  **
25    Supports limited combinations of clock chips and busses.
26    Clock chip must be at address 0x69
27    This driver may crash your system.
28    See doc/chips/icspll for details.
29*/
30
31
32#include <linux/module.h>
33#include <linux/slab.h>
34#include <linux/i2c.h>
35#include <linux/i2c-proc.h>
36#include <linux/init.h>
37#include "version.h"
38
39MODULE_LICENSE("GPL");
40
41/* Addresses to scan */
42#define ADDRESS 0x69
43static unsigned short normal_i2c[] = { ADDRESS, SENSORS_I2C_END };
44static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
45static unsigned int normal_isa[] = { SENSORS_ISA_END };
46static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
47
48/* Insmod parameters */
49SENSORS_INSMOD_1(icspll);
50
51#define ICSPLL_SIZE 7
52#define MAXBLOCK_SIZE 32
53
54/* Each client has this additional data */
55struct icspll_data {
56        struct i2c_client client;
57        int sysctl_id;
58        struct semaphore update_lock;
59        char valid;             /* !=0 if following fields are valid */
60        unsigned long last_updated;     /* In jiffies */
61        u8 data[ICSPLL_SIZE];   /* Register values */
62        int memtype;
63};
64
65static int icspll_attach_adapter(struct i2c_adapter *adapter);
66static int icspll_detach_client(struct i2c_client *client);
67static int icspll_detect(struct i2c_adapter *adapter, int address,
68                       unsigned short flags, int kind);
69
70#if 0
71static int icspll_write_value(struct i2c_client *client, u8 reg,
72                              u16 value);
73#endif
74
75static void icspll_contents(struct i2c_client *client, int operation,
76                            int ctl_name, int *nrels_mag, long *results);
77static void icspll_update_client(struct i2c_client *client);
78
79
80/* This is the driver that will be inserted */
81static struct i2c_driver icspll_driver = {
82        .name           = "Clock chip reader",
83        .id             = I2C_DRIVERID_ICSPLL,
84        .flags          = I2C_DF_NOTIFY,
85        .attach_adapter = icspll_attach_adapter,
86        .detach_client  = icspll_detach_client,
87};
88
89/* -- SENSORS SYSCTL START -- */
90#define ICSPLL_SYSCTL1 1000
91/* -- SENSORS SYSCTL END -- */
92
93/* These files are created for each detected ICSPLL. This is just a template;
94   though at first sight, you might think we could use a statically
95   allocated list, we need some way to get back to the parent - which
96   is done through one of the 'extra' fields which are initialized
97   when a new copy is allocated. */
98static ctl_table icspll_dir_table_template[] = {
99        {ICSPLL_SYSCTL1, "reg0-6", NULL, 0, 0444, NULL, &i2c_proc_real,
100         &i2c_sysctl_real, NULL, &icspll_contents},
101        {0}
102};
103
104/* holding place for data - block read could be as much as 32 */
105static u8 tempdata[MAXBLOCK_SIZE];
106
107static int icspll_attach_adapter(struct i2c_adapter *adapter)
108{
109        return i2c_detect(adapter, &addr_data, icspll_detect);
110}
111
112/* This function is called by i2c_detect */
113int icspll_detect(struct i2c_adapter *adapter, int address,
114                  unsigned short flags, int kind)
115{
116        int err, i;
117        struct i2c_client *new_client;
118        struct icspll_data *data;
119
120        err = 0;
121        /* Make sure we aren't probing the ISA bus!! */
122        if (i2c_is_isa_adapter(adapter))
123                return 0;
124
125        if (address != ADDRESS)
126                return 0;
127
128        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BLOCK_DATA |
129                                     I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
130                printk("icspll.o: Adapter does not support SMBus writes and Block reads\n");
131                goto ERROR0;
132        }
133
134        /* Allocate space for a new client structure */
135        if (!(data = kmalloc(sizeof(struct icspll_data), GFP_KERNEL))) {
136                err = -ENOMEM;
137                goto ERROR0;
138        }
139
140        /* Fill the new client structure with data */
141        new_client = &data->client;
142        new_client->data = data;
143        new_client->addr = address;
144        new_client->adapter = adapter;
145        new_client->driver = &icspll_driver;
146        new_client->flags = 0;
147        strcpy(new_client->name, "Clock chip");
148        data->valid = 0;
149        init_MUTEX(&data->update_lock);
150
151        /* use write-quick for detection */
152        if (i2c_smbus_write_quick(new_client, 0x00) < 0) {
153                printk("icspll.o: No device found at 0x%X\n", address);
154                goto ERROR1;
155        }
156
157        /* fill data structure so unknown registers are 0xFF */
158        data->data[0] = ICSPLL_SIZE;
159        for (i = 1; i <= ICSPLL_SIZE; i++)
160                data->data[i] = 0xFF;
161
162        /* Tell i2c-core a new client has arrived */
163        if ((err = i2c_attach_client(new_client)))
164                goto ERROR2;
165
166        /* Register a new directory entry with module sensors */
167        if ((err = i2c_register_entry(new_client, "icspll",
168                                          icspll_dir_table_template,
169                                          THIS_MODULE)) < 0)
170                goto ERROR3;
171        data->sysctl_id = err;
172        err = 0;
173
174      ERROR3:
175        i2c_detach_client(new_client);
176      ERROR2:
177      ERROR1:
178        kfree(data);
179      ERROR0:
180        return err;
181}
182
183static int icspll_detach_client(struct i2c_client *client)
184{
185        int err;
186
187        i2c_deregister_entry(((struct icspll_data *) (client->data))->
188                                 sysctl_id);
189
190        if ((err = i2c_detach_client(client))) {
191                printk
192                    ("icspll.o: Client deregistration failed, client not detached.\n");
193                return err;
194        }
195
196        kfree(client->data);
197        return 0;
198}
199
200
201#if 0
202/* No writes yet (PAE) */
203static int icspll_write_value(struct i2c_client *client, u8 reg, u16 value)
204{
205        return i2c_smbus_write_block_data(client->adapter, client->addr,
206                                          reg, value);
207}
208#endif
209
210static void icspll_update_client(struct i2c_client *client)
211{
212        struct icspll_data *data = client->data;
213        int i, len;
214
215        down(&data->update_lock);
216
217        if ((jiffies - data->last_updated > HZ + HZ / 2) ||
218            (jiffies < data->last_updated) || !data->valid) {
219
220                len =
221                    i2c_smbus_read_block_data(client,
222                                              0x00,
223                                              tempdata);
224#ifdef DEBUG
225                printk("icspll.o: read returned %d values\n", len);
226#endif
227                if (len > ICSPLL_SIZE)
228                        len = ICSPLL_SIZE;
229                for (i = 0; i < len; i++)
230                        data->data[i] = tempdata[i];
231
232                data->last_updated = jiffies;
233                data->valid = 1;
234        }
235
236        up(&data->update_lock);
237}
238
239
240void icspll_contents(struct i2c_client *client, int operation,
241                     int ctl_name, int *nrels_mag, long *results)
242{
243        int i;
244        struct icspll_data *data = client->data;
245
246        if (operation == SENSORS_PROC_REAL_INFO)
247                *nrels_mag = 0;
248        else if (operation == SENSORS_PROC_REAL_READ) {
249                icspll_update_client(client);
250                for (i = 0; i < ICSPLL_SIZE; i++) {
251                        results[i] = data->data[i];
252                }
253#ifdef DEBUG
254                printk("icspll.o: 0x%X ICSPLL Contents: ", client->addr);
255                for (i = 0; i < ICSPLL_SIZE; i++) {
256                        printk(" 0x%X", data->data[i]);
257                }
258                printk(" .\n");
259#endif
260                *nrels_mag = ICSPLL_SIZE;
261        } else if (operation == SENSORS_PROC_REAL_WRITE) {
262
263/* No writes to the ICSPLL (yet, anyway) (PAE) */
264                printk("icspll.o: No writes to ICSPLLs supported!\n");
265        }
266}
267
268static int __init sm_icspll_init(void)
269{
270        printk("icspll.o version %s (%s)\n", LM_VERSION, LM_DATE);
271        return i2c_add_driver(&icspll_driver);
272}
273
274static void __exit sm_icspll_exit(void)
275{
276        i2c_del_driver(&icspll_driver);
277}
278
279
280
281MODULE_AUTHOR
282    ("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark Studebaker <mdsxyz123@yahoo.com>");
283MODULE_DESCRIPTION("ICSPLL driver");
284
285module_init(sm_icspll_init);
286module_exit(sm_icspll_exit);
Note: See TracBrowser for help on using the browser.