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

Revision 499, 17.1 KB (checked in by kmalkki, 14 years ago)

(Kyösti)

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