root/lm-sensors/trunk/kernel/chips/bt869.c @ 513

Revision 513, 17.3 KB (checked in by frodo, 15 years ago)

First step to make it possible to integrate lm_sensors modules into

the kernel.

* <kernel/init.h> is now included for all modules
* Initialization-time only functions and variables are marked with init
* EXPORT_SYMBOL or EXPORT_NO_SYMBOLS declarations added

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    bt869.c - Part of lm_sensors, Linux kernel modules for hardware
3             monitoring
4    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
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
22#define DEBUG 1
23
24#include <linux/module.h>
25#include <linux/malloc.h>
26#include <linux/i2c.h>
27#include "sensors.h"
28#include "i2c-isa.h"
29#include "version.h"
30#include "compat.h"
31#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,53)
32#include <linux/init.h>
33#else
34#define __init
35#endif
36
37
38/* Addresses to scan */
39static unsigned short normal_i2c[] = {SENSORS_I2C_END};
40
41/* found only at 0x44 or 0x45 */
42static unsigned short normal_i2c_range[] = {0x44,0x45,SENSORS_I2C_END};
43static unsigned int normal_isa[] = {SENSORS_ISA_END};
44static unsigned int normal_isa_range[] = {SENSORS_ISA_END};
45
46/* Insmod parameters */
47SENSORS_INSMOD_1(bt869);
48
49/* Many bt869 constants specified below */
50
51/* The bt869 registers */
52/* Coming soon: Many, many registers */
53
54/* Conversions. Rounding and limit checking is only done on the TO_REG
55   variants. Note that you should be a bit careful with which arguments
56   these macros are called: arguments may be evaluated more than once.
57   Fixing this is just not worth it. */
58   
59   /*none*/
60
61/* Initial values */
62/*none*/
63
64/* Each client has this additional data */
65struct bt869_data {
66         int sysctl_id;
67
68         struct semaphore update_lock;
69         char valid;                 /* !=0 if following fields are valid */
70         unsigned long last_updated; /* In jiffies */
71
72         u8 status[3]; /* Register values */
73         u16 res[2]; /* Resolution XxY */
74         u8 ntsc; /* 1=NTSC, 0=PAL */
75         u8 half; /* go half res */
76         u8 depth; /* screen depth */
77         u8 colorbars; /* turn on/off colorbar calibration screen */
78};
79
80#ifdef MODULE
81extern int init_module(void);
82extern int cleanup_module(void);
83#endif /* MODULE */
84
85static int __init bt869_init(void);
86static int __init bt869_cleanup(void);
87static int bt869_attach_adapter(struct i2c_adapter *adapter);
88static int bt869_detect(struct i2c_adapter *adapter, int address, int kind);
89static void bt869_init_client(struct i2c_client *client);
90static int bt869_detach_client(struct i2c_client *client);
91static int bt869_command(struct i2c_client *client, unsigned int cmd,
92                        void *arg);
93static void bt869_inc_use (struct i2c_client *client);
94static void bt869_dec_use (struct i2c_client *client);
95static int bt869_read_value(struct i2c_client *client, u8 reg);
96static int bt869_write_value(struct i2c_client *client, u8 reg, u16 value);
97static void bt869_status(struct i2c_client *client, int operation, int ctl_name,
98                      int *nrels_mag, long *results);
99static void bt869_ntsc(struct i2c_client *client, int operation, int ctl_name,
100                      int *nrels_mag, long *results);
101static void bt869_res(struct i2c_client *client, int operation, int ctl_name,
102                      int *nrels_mag, long *results);
103static void bt869_half(struct i2c_client *client, int operation, int ctl_name,
104                      int *nrels_mag, long *results);
105static void bt869_colorbars(struct i2c_client *client, int operation, int ctl_name,
106                      int *nrels_mag, long *results);
107static void bt869_depth(struct i2c_client *client, int operation, int ctl_name,
108                      int *nrels_mag, long *results);
109static void bt869_update_client(struct i2c_client *client);
110
111
112/* This is the driver that will be inserted */
113static struct i2c_driver bt869_driver = {
114  /* name */            "BT869 video-output chip driver",
115  /* id */              I2C_DRIVERID_BT869,
116  /* flags */           I2C_DF_NOTIFY,
117  /* attach_adapter */  &bt869_attach_adapter,
118  /* detach_client */   &bt869_detach_client,
119  /* command */         &bt869_command,
120  /* inc_use */         &bt869_inc_use,
121  /* dec_use */         &bt869_dec_use
122};
123
124/* These files are created for each detected bt869. This is just a template;
125   though at first sight, you might think we could use a statically
126   allocated list, we need some way to get back to the parent - which
127   is done through one of the 'extra' fields which are initialized
128   when a new copy is allocated. */
129static ctl_table bt869_dir_table_template[] = {
130  { BT869_SYSCTL_STATUS, "status", NULL, 0, 0444, NULL, &sensors_proc_real,
131    &sensors_sysctl_real, NULL, &bt869_status },
132  { BT869_SYSCTL_NTSC, "ntsc", NULL, 0, 0644, NULL, &sensors_proc_real,
133    &sensors_sysctl_real, NULL, &bt869_ntsc },
134  { BT869_SYSCTL_RES, "res", NULL, 0, 0644, NULL, &sensors_proc_real,
135    &sensors_sysctl_real, NULL, &bt869_res },
136  { BT869_SYSCTL_HALF, "half", NULL, 0, 0644, NULL, &sensors_proc_real,
137    &sensors_sysctl_real, NULL, &bt869_half },
138  { BT869_SYSCTL_COLORBARS, "colorbars", NULL, 0, 0644, NULL, &sensors_proc_real,
139    &sensors_sysctl_real, NULL, &bt869_colorbars },
140  { BT869_SYSCTL_DEPTH, "depth", NULL, 0, 0644, NULL, &sensors_proc_real,
141    &sensors_sysctl_real, NULL, &bt869_depth },
142  { 0 }
143};
144
145/* Used by init/cleanup */
146static int __init bt869_initialized = 0;
147
148/* I choose here for semi-static bt869 allocation. Complete dynamic
149   allocation could also be used; the code needed for this would probably
150   take more memory than the datastructure takes now. */
151#define MAX_bt869_NR 16
152static struct i2c_client *bt869_list[MAX_bt869_NR];
153
154
155int bt869_attach_adapter(struct i2c_adapter *adapter)
156{
157  return sensors_detect(adapter,&addr_data,bt869_detect);
158}
159
160/* This function is called by sensors_detect */
161int bt869_detect(struct i2c_adapter *adapter, int address, int kind)
162{
163  int i,cur;
164  struct i2c_client *new_client;
165  struct bt869_data *data;
166  int err=0;
167  const char *type_name,*client_name;
168
169
170printk("bt869.o:  probing address %d .\n",address);
171  /* Make sure we aren't probing the ISA bus!! This is just a safety check
172     at this moment; sensors_detect really won't call us. */
173#ifdef DEBUG
174  if (i2c_is_isa_adapter(adapter)) {
175    printk("bt869.o: bt869_detect called for an ISA bus adapter?!?\n");
176    return 0;
177  }
178#endif
179
180  /* Here, we have to do the address registration check for the I2C bus.
181     But that is not yet implemented. */
182
183  /* OK. For now, we presume we have a valid client. We now create the
184     client structure, even though we cannot fill it completely yet.
185     But it allows us to access bt869_{read,write}_value. */
186  if (! (new_client = kmalloc(sizeof(struct i2c_client) +
187                              sizeof(struct bt869_data),
188                              GFP_KERNEL))) {
189    err = -ENOMEM;
190    goto ERROR0;
191  }
192
193  data = (struct bt869_data *) (((struct i2c_client *) new_client) + 1);
194  new_client->addr = address;
195  new_client->data = data;
196  new_client->adapter = adapter;
197  new_client->driver = &bt869_driver;
198
199  /* Now, we do the remaining detection. It is lousy. */
200  i2c_smbus_write_byte_data(new_client->adapter,
201        new_client->addr,0xC4,0);         /* set status bank 0 */
202  cur = i2c_smbus_read_byte(adapter,address);
203  printk("bt869.o: address 0x%X testing-->0x%X\n",address,cur);
204  if ((cur | 0x20) != 0x22)
205      goto ERROR1;
206     
207  /* Determine the chip type */
208  kind = ((cur & 0x20)>>5);
209
210  if (kind) {
211    type_name = "bt869";
212    client_name = "bt869 chip";
213    printk("bt869.o: BT869 detected\n");
214  } else {
215    type_name = "bt868";
216    client_name = "bt868 chip";
217    printk("bt869.o: BT868 detected\n");
218  }
219 
220  /* Fill in the remaining client fields and put it into the global list */
221  strcpy(new_client->name,client_name);
222
223  /* Find a place in our global list */
224  for (i = 0; i < MAX_bt869_NR; i++)
225    if (! bt869_list[i])
226       break;
227  if (i == MAX_bt869_NR) {
228    err = -ENOMEM;
229    printk("bt869.o: No empty slots left, recompile and heighten "
230           "MAX_bt869_NR!\n");
231    goto ERROR2;
232  }
233  bt869_list[i] = new_client;
234  new_client->id = i;
235  data->valid = 0;
236  init_MUTEX(&data->update_lock);
237   
238  /* Tell the I2C layer a new client has arrived */
239  if ((err = i2c_attach_client(new_client)))
240    goto ERROR3;
241
242  /* Register a new directory entry with module sensors */
243  if ((i = sensors_register_entry(new_client,type_name,
244                                  bt869_dir_table_template)) < 0) {
245    err = i;
246    goto ERROR4;
247  }
248  data->sysctl_id = i;
249
250  bt869_init_client((struct i2c_client *) new_client);
251  return 0;
252
253/* OK, this is not exactly good programming practice, usually. But it is
254   very code-efficient in this case. */
255
256ERROR4:
257  i2c_detach_client(new_client);
258ERROR3:
259  for (i = 0; i < MAX_bt869_NR; i++)
260    if (new_client == bt869_list[i])
261      bt869_list[i] = NULL;
262ERROR2:
263ERROR1:
264  kfree(new_client);
265ERROR0:
266  return err;
267}
268
269int bt869_detach_client(struct i2c_client *client)
270{
271  int err,i;
272
273  sensors_deregister_entry(((struct bt869_data *)(client->data))->sysctl_id);
274
275  if ((err = i2c_detach_client(client))) {
276    printk("bt869.o: Client deregistration failed, client not detached.\n");
277    return err;
278  }
279
280  for (i = 0; i < MAX_bt869_NR; i++)
281    if (client == bt869_list[i])
282      break;
283  if ((i == MAX_bt869_NR)) {
284    printk("bt869.o: Client to detach not found.\n");
285    return -ENOENT;
286  }
287  bt869_list[i] = NULL;
288
289  kfree(client);
290
291  return 0;
292}
293
294
295/* No commands defined yet */
296int bt869_command(struct i2c_client *client, unsigned int cmd, void *arg)
297{
298  return 0;
299}
300
301/* Nothing here yet */
302void bt869_inc_use (struct i2c_client *client)
303{
304#ifdef MODULE
305  MOD_INC_USE_COUNT;
306#endif
307}
308
309/* Nothing here yet */
310void bt869_dec_use (struct i2c_client *client)
311{
312#ifdef MODULE
313  MOD_DEC_USE_COUNT;
314#endif
315}
316
317/* All registers are byte-sized.
318   bt869 uses a high-byte first convention, which is exactly opposite to
319   the usual practice. */
320int bt869_read_value(struct i2c_client *client, u8 reg)
321{
322    return i2c_smbus_read_byte(client->adapter,client->addr);
323}
324
325/* All registers are byte-sized.
326   bt869 uses a high-byte first convention, which is exactly opposite to
327   the usual practice. */
328int bt869_write_value(struct i2c_client *client, u8 reg, u16 value)
329{
330    return i2c_smbus_write_byte_data(client->adapter,client->addr,reg,value);
331}
332
333void bt869_init_client(struct i2c_client *client)
334{
335  struct bt869_data *data = client->data;
336 
337    /* Initialize the bt869 chip */
338    bt869_write_value(client,0x0ba,0x80);
339 //   bt869_write_value(client,0x0D6, 0x00);
340    /* Be a slave to the clock on the Voodoo3 */
341    bt869_write_value(client,0xa0,0x80);
342    bt869_write_value(client,0xba,0x20);
343    /* depth =16bpp */
344    bt869_write_value(client,0x0C6, 0x001);
345    bt869_write_value(client,0xC4,1);
346    /* Flicker free enable and config */
347    bt869_write_value(client,0xC8,0);
348    data->res[0]=640;
349    data->res[1]=480;
350    data->ntsc=1;
351    data->half=0;
352    data->colorbars=0;
353    data->depth=16;
354   
355}
356
357void bt869_update_client(struct i2c_client *client)
358{
359  struct bt869_data *data = client->data;
360
361  down(&data->update_lock);
362
363  if ((jiffies - data->last_updated > HZ+HZ/2 ) ||
364      (jiffies < data->last_updated) || ! data->valid) {
365#ifdef DEBUG
366    printk("Starting bt869 update\n");
367#endif
368/* Set values of device */
369    if ((data->res[0] == 640) && (data->res[1] == 480)) {
370      bt869_write_value(client,0xB8,(! data->ntsc));
371      bt869_write_value(client,0xa0,0x80 + 0x0C);
372      printk("bt869.o: writing into config -->0x%X\n",(0 + (! data->ntsc)));
373    } else if ((data->res[0] == 800) && (data->res[1] == 600)) {
374      bt869_write_value(client,0xB8,(2 + (! data->ntsc)));
375      bt869_write_value(client,0xa0,0x80 + 0x11);
376      printk("bt869.o: writing into config -->0x%X\n",(2 + (! data->ntsc)));
377    } else {
378      bt869_write_value(client,0xB8,(! data->ntsc));
379      bt869_write_value(client,0xa0,0x80 + 0x0C);
380      printk("bt869.o: writing into config -->0x%X\n",(0 + (! data->ntsc)));
381      printk("bt869.o:  Warning: arbitrary resolutions not supported yet.  Using 640x480.\n");
382      data->res[0] = 640;
383      data->res[1] = 480;
384    }
385    if ((data->depth!=24) && (data->depth!=16))
386      data->depth=16;
387    if (data->depth==16)
388      bt869_write_value(client,0x0C6, 0x001);
389    if (data->depth==24)
390      bt869_write_value(client,0x0C6, 0x000);
391    bt869_write_value(client,0xD4,data->half<<6);
392    /* Be a slave to the clock on the Voodoo3 */
393    bt869_write_value(client,0xba,0x20);
394    /* depth =16bpp */
395    bt869_write_value(client,0x0C6, 0x001);
396    bt869_write_value(client,0xC4,1);
397
398/* Get status */
399    bt869_write_value(client,0xC4,1 | (data->colorbars << 2));
400    data->status[0] = bt869_read_value(client,1);
401    bt869_write_value(client,0xC4,0x41 | (data->colorbars << 2));
402    data->status[1] = bt869_read_value(client,1);
403    bt869_write_value(client,0xC4,0x81 | (data->colorbars << 2));
404    data->status[2] = bt869_read_value(client,1);
405    bt869_write_value(client,0xC4,0x0C1 | (data->colorbars << 2));
406    data->last_updated = jiffies;
407    data->valid = 1;
408  }
409  up(&data->update_lock);
410}
411
412
413void bt869_status(struct i2c_client *client, int operation, int ctl_name,
414               int *nrels_mag, long *results)
415{
416  struct bt869_data *data = client->data;
417  if (operation == SENSORS_PROC_REAL_INFO)
418    *nrels_mag = 0;
419  else if (operation == SENSORS_PROC_REAL_READ) {
420    bt869_update_client(client);
421    results[0] = data->status[0];
422    results[1] = data->status[1];
423    results[2] = data->status[2];
424    *nrels_mag = 3;
425  } else if (operation == SENSORS_PROC_REAL_WRITE) {
426        printk("bt869.o: Warning: write was requested on read-only proc file: status\n");
427  }
428}
429
430
431void bt869_ntsc(struct i2c_client *client, int operation, int ctl_name,
432               int *nrels_mag, long *results)
433{
434  struct bt869_data *data = client->data;
435  if (operation == SENSORS_PROC_REAL_INFO)
436    *nrels_mag = 0;
437  else if (operation == SENSORS_PROC_REAL_READ) {
438    bt869_update_client(client);
439    results[0] = data->ntsc;
440    *nrels_mag = 1;
441  } else if (operation == SENSORS_PROC_REAL_WRITE) {
442    if (*nrels_mag >= 1) {
443      data->ntsc = (results[0] > 0);
444    }
445    bt869_update_client(client);
446  }
447}
448
449
450void bt869_res(struct i2c_client *client, int operation, int ctl_name,
451               int *nrels_mag, long *results)
452{
453  struct bt869_data *data = client->data;
454  if (operation == SENSORS_PROC_REAL_INFO)
455    *nrels_mag = 0;
456  else if (operation == SENSORS_PROC_REAL_READ) {
457    bt869_update_client(client);
458    results[0] = data->res[0];
459    results[1] = data->res[1];
460    *nrels_mag = 2;
461  } else if (operation == SENSORS_PROC_REAL_WRITE) {
462    if (*nrels_mag >= 1) {
463      data->res[0] = results[0];
464    }
465    if (*nrels_mag >= 2) {
466      data->res[1] = results[1];
467    }
468    bt869_update_client(client);
469  }
470}
471
472
473void bt869_half(struct i2c_client *client, int operation, int ctl_name,
474               int *nrels_mag, long *results)
475{
476  struct bt869_data *data = client->data;
477  if (operation == SENSORS_PROC_REAL_INFO)
478    *nrels_mag = 0;
479  else if (operation == SENSORS_PROC_REAL_READ) {
480    bt869_update_client(client);
481    results[0] = data->half;
482    *nrels_mag = 1;
483  } else if (operation == SENSORS_PROC_REAL_WRITE) {
484    if (*nrels_mag >= 1) {
485      data->half = (results[0] > 0);
486      bt869_update_client(client);
487    }
488  }
489}
490
491void bt869_colorbars(struct i2c_client *client, int operation, int ctl_name,
492               int *nrels_mag, long *results)
493{
494  struct bt869_data *data = client->data;
495  if (operation == SENSORS_PROC_REAL_INFO)
496    *nrels_mag = 0;
497  else if (operation == SENSORS_PROC_REAL_READ) {
498    bt869_update_client(client);
499    results[0] = data->colorbars;
500    *nrels_mag = 1;
501  } else if (operation == SENSORS_PROC_REAL_WRITE) {
502    if (*nrels_mag >= 1) {
503      data->colorbars = (results[0] > 0);
504      bt869_update_client(client);
505    }
506  }
507}
508
509void bt869_depth(struct i2c_client *client, int operation, int ctl_name,
510               int *nrels_mag, long *results)
511{
512  struct bt869_data *data = client->data;
513  if (operation == SENSORS_PROC_REAL_INFO)
514    *nrels_mag = 0;
515  else if (operation == SENSORS_PROC_REAL_READ) {
516    bt869_update_client(client);
517    results[0] = data->depth;
518    *nrels_mag = 1;
519  } else if (operation == SENSORS_PROC_REAL_WRITE) {
520    if (*nrels_mag >= 1) {
521      data->depth = results[0];
522      bt869_update_client(client);
523    }
524  }
525}
526
527int __init bt869_init(void)
528{
529  int res;
530
531  printk("bt869.o version %s (%s)\n",LM_VERSION,LM_DATE);
532  bt869_initialized = 0;
533  if ((res = i2c_add_driver(&bt869_driver))) {
534    printk("bt869.o: Driver registration failed, module not inserted.\n");
535    bt869_cleanup();
536    return res;
537  }
538  bt869_initialized ++;
539  return 0;
540}
541
542int __init bt869_cleanup(void)
543{
544  int res;
545
546  if (bt869_initialized >= 1) {
547    if ((res = i2c_del_driver(&bt869_driver))) {
548      printk("bt869.o: Driver deregistration failed, module not removed.\n");
549      return res;
550    }
551    bt869_initialized --;
552  }
553
554  return 0;
555}
556
557EXPORT_NO_SYMBOLS;
558
559#ifdef MODULE
560
561MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
562MODULE_DESCRIPTION("bt869 driver");
563
564int init_module(void)
565{
566  return bt869_init();
567}
568
569int cleanup_module(void)
570{
571  return bt869_cleanup();
572}
573
574#endif /* MODULE */
575
Note: See TracBrowser for help on using the browser.