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

Revision 467, 9.8 KB (checked in by frodo, 14 years ago)

Bradley M. Keryan's patches to make lm_sensors compile against
2.3.x kernels (x >= 1).

  • 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 <mds@eng.paradyne.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    Use on unsupported chips may crash your system.
27    See doc/chips/icspll for details.
28*/
29
30
31#include <linux/module.h>
32#include <linux/malloc.h>
33#include "smbus.h"
34#include "sensors.h"
35#include "i2c.h"
36#include "i2c-isa.h"
37#include "version.h"
38
39/* Many constants specified below */
40
41#define ICSPLL_SIZE 7
42#define MAXBLOCK_SIZE 32
43
44/* Each client has this additional data */
45struct icspll_data {
46         int sysctl_id;
47
48         struct semaphore update_lock;
49         char valid;                 /* !=0 if following fields are valid */
50         unsigned long last_updated; /* In jiffies */
51
52         u8 data[ICSPLL_SIZE];     /* Register values */
53         int memtype;
54};
55
56#ifdef MODULE
57extern int init_module(void);
58extern int cleanup_module(void);
59#endif /* MODULE */
60
61static int icspll_init(void);
62static int icspll_cleanup(void);
63
64static int icspll_attach_adapter(struct i2c_adapter *adapter);
65static int icspll_detach_client(struct i2c_client *client);
66static int icspll_command(struct i2c_client *client, unsigned int cmd,
67                        void *arg);
68                       
69static void icspll_inc_use (struct i2c_client *client);
70static void icspll_dec_use (struct i2c_client *client);
71
72#if 0
73static int icspll_write_value(struct i2c_client *client, u8 reg, u16 value);
74#endif
75
76static void icspll_contents(struct i2c_client *client, int operation, int ctl_name,
77                      int *nrels_mag, long *results);
78static void icspll_update_client(struct i2c_client *client);
79
80
81/* This is the driver that will be inserted */
82static struct i2c_driver icspll_driver = {
83  /* name */            "ICS/PLL clock reader",
84  /* id */              I2C_DRIVERID_ICSPLL,
85  /* flags */           DF_NOTIFY,
86  /* attach_adapter */  &icspll_attach_adapter,
87  /* detach_client */   &icspll_detach_client,
88  /* command */         &icspll_command,
89  /* inc_use */         &icspll_inc_use,
90  /* dec_use */         &icspll_dec_use
91};
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, &sensors_proc_real,
100    &sensors_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
107/* Used by init/cleanup */
108static int icspll_initialized = 0;
109
110/* I choose here for semi-static allocation. Complete dynamic
111   allocation could also be used; the code needed for this would probably
112   take more memory than the datastructure takes now. */
113#define MAX_ICSPLL_NR 2
114static struct i2c_client *icspll_list[MAX_ICSPLL_NR];
115
116
117int icspll_attach_adapter(struct i2c_adapter *adapter)
118{
119  int address,err,i;
120  struct i2c_client *new_client;
121  struct icspll_data *data;
122
123  err = 0;
124  /* Make sure we aren't probing the ISA bus!! */
125  if (i2c_is_isa_adapter(adapter)) return 0;
126 
127  /* OK, this is no detection. I know. It will do for now, though.  */
128
129  /* Set err only if a global error would make registering other clients
130     impossible too (like out-of-memory). */
131     
132  /* ICS and PLL clock chips seem to all be at 0x69.
133     Don't know what is out there at 0x6A, don't scan that yet. */
134
135  for (address = 0x69; (! err) && (address <= 0x69); address ++) {
136
137    /* Later on, we will keep a list of registered addresses for each
138       adapter, and check whether they are used here */
139   
140    /* these chips only support block transfers so use that for detection */
141    if(smbus_read_block_data(adapter, address, 0x00, tempdata) < 0) {
142#ifdef DEBUG
143      printk("icspll.o: No icspll found at: 0x%X\n",address);
144#endif
145      continue;
146    }
147
148    /* Real detection code goes here */
149
150    /* Allocate space for a new client structure */
151    if (! (new_client =  kmalloc(sizeof(struct i2c_client) +
152                                sizeof(struct icspll_data),
153                               GFP_KERNEL))) {
154      err = -ENOMEM;
155      continue;
156    }
157
158    /* Find a place in our global list */
159    for (i = 0; i < MAX_ICSPLL_NR; i++)
160      if (! icspll_list[i])
161         break;
162    if (i == MAX_ICSPLL_NR) {
163      err = -ENOMEM;
164      printk("icspll.o: No empty slots left, recompile and heighten "
165             "MAX_ICSPLL_NR!\n");
166      goto ERROR1;
167    }
168    icspll_list[i] = new_client;
169   
170    /* Fill the new client structure with data */
171    data = (struct icspll_data *) (new_client + 1);
172    new_client->data = data;
173    new_client->id = i;
174    new_client->addr = address;
175    new_client->adapter = adapter;
176    new_client->driver = &icspll_driver;
177    strcpy(new_client->name,"ICSPLL chip");
178    data->valid = 0;
179    init_MUTEX(&data->update_lock);
180/* fill data structure so unknown registers are 0xFF */
181    data->data[0] = ICSPLL_SIZE;
182    for(i = 1; i <= ICSPLL_SIZE; i++)
183      data->data[i] = 0xFF;
184   
185    /* Tell i2c-core a new client has arrived */
186    if ((err = i2c_attach_client(new_client)))
187      goto ERROR2;
188   
189    /* Register a new directory entry with module sensors */
190    if ((err = sensors_register_entry(new_client,"icspll",
191                                      icspll_dir_table_template)) < 0)
192      goto ERROR3;
193    data->sysctl_id = err;
194    err = 0;
195
196    continue;
197/* OK, this is not exactly good programming practice, usually. But it is
198   very code-efficient in this case. */
199
200ERROR3:
201    i2c_detach_client(new_client);
202ERROR2:
203    icspll_list[i] = NULL;
204ERROR1:
205    kfree(new_client);
206  }
207  return err;
208}
209
210int icspll_detach_client(struct i2c_client *client)
211{
212  int err,i;
213  for (i = 0; i < MAX_ICSPLL_NR; i++)
214    if (client == icspll_list[i])
215      break;
216  if ((i == MAX_ICSPLL_NR)) {
217    printk("icspll.o: Client to detach not found.\n");
218    return -ENOENT;
219  }
220
221  sensors_deregister_entry(((struct icspll_data *)(client->data))->sysctl_id);
222
223  if ((err = i2c_detach_client(client))) {
224    printk("icspll.o: Client deregistration failed, client not detached.\n");
225    return err;
226  }
227
228  icspll_list[i] = NULL;
229  kfree(client);
230  return 0;
231}
232
233
234/* No commands defined yet */
235int icspll_command(struct i2c_client *client, unsigned int cmd, void *arg)
236{
237  return 0;
238}
239
240void icspll_inc_use (struct i2c_client *client)
241{
242#ifdef MODULE
243  MOD_INC_USE_COUNT;
244#endif
245}
246
247void icspll_dec_use (struct i2c_client *client)
248{
249#ifdef MODULE
250  MOD_DEC_USE_COUNT;
251#endif
252}
253
254#if 0
255/* No writes yet (PAE) */
256int icspll_write_value(struct i2c_client *client, u8 reg, u16 value)
257{
258  return smbus_write_block_data(client->adapter,client->addr,reg,value);
259}
260#endif
261
262void icspll_update_client(struct i2c_client *client)
263{
264  struct icspll_data *data = client->data;
265  int i, len;
266
267  down(&data->update_lock);
268
269  if ((jiffies - data->last_updated > HZ+HZ/2 ) ||
270      (jiffies < data->last_updated) || ! data->valid) {
271
272    len = smbus_read_block_data(client->adapter, client->addr, 0x00, tempdata);
273#ifdef DEBUG
274    printk("icspll.o: read returned %d values\n", len);
275#endif
276    if(len > ICSPLL_SIZE)
277      len = ICSPLL_SIZE;
278    for(i = 0; i < len; i++)
279      data->data[i] = tempdata[i];
280   
281    data->last_updated = jiffies;
282    data->valid = 1;
283  }
284
285  up(&data->update_lock);
286}
287
288
289void icspll_contents(struct i2c_client *client, int operation, int ctl_name,
290               int *nrels_mag, long *results)
291{
292  int i;
293  struct icspll_data *data = client->data;
294 
295  if (operation == SENSORS_PROC_REAL_INFO)
296    *nrels_mag = 0;
297  else if (operation == SENSORS_PROC_REAL_READ) {
298    icspll_update_client(client);
299    for (i=0; i< ICSPLL_SIZE; i++) {
300        results[i]=data->data[i];
301    }
302#ifdef DEBUG
303    printk("icspll.o: 0x%X ICSPLL Contents: ",client->addr);
304    for (i=0; i< ICSPLL_SIZE; i++) {
305      printk(" 0x%X",data->data[i]);
306    }
307    printk(" .\n");
308#endif
309    *nrels_mag = ICSPLL_SIZE;
310  } else if (operation == SENSORS_PROC_REAL_WRITE) {
311
312/* No writes to the ICSPLL (yet, anyway) (PAE) */
313    printk("icspll.o: No writes to ICSPLLs supported!\n");
314  }
315}
316
317int icspll_init(void)
318{
319  int res;
320
321  printk("icspll.o version %s (%s)\n",LM_VERSION,LM_DATE);
322  icspll_initialized = 0;
323  if ((res = i2c_add_driver(&icspll_driver))) {
324    printk("icspll.o: Driver registration failed, module not inserted.\n");
325    icspll_cleanup();
326    return res;
327  }
328  icspll_initialized ++;
329  return 0;
330}
331
332int icspll_cleanup(void)
333{
334  int res;
335
336  if (icspll_initialized >= 1) {
337    if ((res = i2c_del_driver(&icspll_driver))) {
338      printk("icspll.o: Driver deregistration failed, module not removed.\n");
339      return res;
340    }
341  } else
342    icspll_initialized --;
343
344  return 0;
345}
346
347
348#ifdef MODULE
349
350MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark Studebaker <mds@eng.paradyne.com>");
351MODULE_DESCRIPTION("ICSPLL driver");
352
353int init_module(void)
354{
355  return icspll_init();
356}
357
358int cleanup_module(void)
359{
360  return icspll_cleanup();
361}
362
363#endif /* MODULE */
364
Note: See TracBrowser for help on using the browser.