root/lm-sensors/trunk/kernel/busses/i2c-piix4.c @ 146

Revision 146, 12.4 KB (checked in by frodo, 14 years ago)

New file CHANGES

Read the intro; it describes how you can use CVS to diff between old releases.

Stupid copyright typo in piix4.c fixed

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    piix4.c - Part of lm_sensors, Linux kernel modules for hardware
3              monitoring
4    Copyright (c) 1998  Frodo Looijaard <frodol@dds.nl> and
5    Philip Edelbrock <phil@netroedge.com>
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22/* Note: we assume there can only be one PIIX4, with one SMBus interface */
23
24#include <linux/module.h>
25#include <linux/pci.h>
26#include <asm/io.h>
27#include <linux/kernel.h>
28#include <linux/stddef.h>
29#include <linux/sched.h>
30#include <linux/ioport.h>
31#include "smbus.h"
32#include "version.h"
33#include "compat.h"
34
35#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,54))
36#include <linux/bios32.h>
37#endif
38
39
40/* PIIX4 SMBus address offsets */
41#define SMBHSTSTS (0 + piix4_smba)
42#define SMBHSLVSTS (1 + piix4_smba)
43#define SMBHSTCNT (2 + piix4_smba)
44#define SMBHSTCMD (3 + piix4_smba)
45#define SMBHSTADD (4 + piix4_smba)
46#define SMBHSTDAT0 (5 + piix4_smba)
47#define SMBHSTDAT1 (6 + piix4_smba)
48#define SMBBLKDAT (7 + piix4_smba)
49#define SMBSLVCNT (8 + piix4_smba)
50#define SMBSHDWCMD (9 + piix4_smba)
51#define SMBSLVEVT (0xA + piix4_smba)
52#define SMBSLVDAT (0xC + piix4_smba)
53
54/* PCI Address Constants */
55#define SMBBA     0x090
56#define SMBHSTCFG 0x0D2
57#define SMBSLVC   0x0D3
58#define SMBSHDW1  0x0D4
59#define SMBSHDW2  0x0D5
60#define SMBREV    0x0D6
61
62/* Other settings */
63#define MAX_TIMEOUT 500
64#define  ENABLE_INT9 0
65
66/* PIIX4 constants */
67#define PIIX4_QUICK      0x00
68#define PIIX4_BYTE       0x04
69#define PIIX4_BYTE_DATA  0x08
70#define PIIX4_WORD_DATA  0x0C
71#define PIIX4_BLOCK_DATA 0x14
72
73
74static int piix4_init(void);
75static int piix4_cleanup(void);
76static int piix4_setup(void);
77static s32 piix4_access(u8 addr, char read_write,
78                        u8 command, int size, union smbus_data * data);
79static void piix4_do_pause( unsigned int amount );
80static int piix4_transaction(void);
81
82#ifdef MODULE
83extern int init_module(void);
84extern int cleanup_module(void);
85#endif /* MODULE */
86
87static struct smbus_adapter piix4_adapter;
88static int piix4_initialized;
89static unsigned short piix4_smba = 0;
90
91
92/* Detect whether a PIIX4 can be found, and initialize it, where necessary.
93   Note the differences between kernels with the old PCI BIOS interface and
94   newer kernels with the real PCI interface. In compat.h some things are
95   defined to make the transition easier. */
96int piix4_setup(void)
97{
98  int error_return=0;
99  unsigned char temp;
100
101#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,54))
102  struct pci_dev *PIIX4_dev;
103#else
104  unsigned char PIIX4_bus, PIIX4_devfn;
105  int i,res;
106#endif
107
108  /* First check whether we can access PCI at all */
109  if (pci_present() == 0) {
110    printk("piix4.o: Error: No PCI-bus found!\n");
111    error_return=-ENODEV;
112    goto END;
113  }
114
115  /* Look for the PIIX4, function 3 */
116#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,54))
117  /* Note: we keep on searching until we have found 'function 3' */
118  PIIX4_dev = NULL;
119  do
120    PIIX4_dev = pci_find_device(PCI_VENDOR_ID_INTEL, 
121                                PCI_DEVICE_ID_INTEL_82371AB_3, PIIX4_dev);
122  while(PIIX4_dev && (PCI_FUNC(PIIX4_dev->devfn) != 3));
123  if(PIIX4_dev == NULL) {
124#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,54) */
125  for (i = 0; 
126       ! (res = pcibios_find_device(PCI_VENDOR_ID_INTEL,
127                                    PCI_DEVICE_ID_INTEL_82371AB_3,
128                                    i,&PIIX4_bus, &PIIX4_devfn)) && 
129         PCI_FUNC(PIIX4_devfn) != 3; 
130       i++);
131     
132  if (res) {
133#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,54) */
134    printk("piix4.o: Error: Can't detect PIIX4, function 3!\n");
135    error_return=-ENODEV;
136    goto END;
137  } 
138
139/* Determine the address of the SMBus areas */
140  pci_read_config_word_united(PIIX4_dev, PIIX4_bus ,PIIX4_devfn,
141                              SMBBA,&piix4_smba);
142  piix4_smba &= 0xfff0;
143
144  if (check_region(piix4_smba, 8)) {
145    printk("piix4.o: PIIX4_smb region 0x%x already in use!\n", piix4_smba);
146    error_return=-ENODEV;
147    goto END;
148  }
149
150  pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn, 
151                              SMBHSTCFG, &temp);
152
153
154#ifdef FORCE_PIIX4_ENABLE
155/* This should never need to be done, but has been noted that
156   many Dell machines have the SMBus interface on the PIIX4
157   disabled!? NOTE: This assumes I/O space and other allocations WERE
158   done by the Bios!  Don't complain if your hardware does weird
159   things after enabling this. :') Check for Bios updates before
160   resorting to this.  */
161  if ((temp & 1) == 0) {
162    pci_write_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn,
163                                     SMBHSTCFG, temp | 1);
164    printk("piix4.0: WARNING: PIIX4 SMBus interface has been FORCEFULLY "
165           "ENABLED!!\n");
166    /* Update configuration value */
167    pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn,
168                                SMBHSTCFG, &temp);
169    /* Note: We test the bit again in the next 'if' just to be sure... */
170  }
171#endif /* FORCE_PIIX4_ENABLE */
172
173  if ((temp & 1) == 0) {
174    printk("SMBUS: Error: Host SMBus controller not enabled!\n");     
175    error_return=-ENODEV;
176    goto END;
177  }
178
179  /* Everything is happy, let's grab the memory and set things up. */
180  request_region(piix4_smba, 8, "piix4");       
181
182#ifdef DEBUG
183  if ((temp & 0x0E) == 8)
184     printk("piix4.o: PIIX4 using Interrupt 9 for SMBus.\n");
185  else if ((temp & 0x0E) == 0)
186     printk("piix4.o: PIIX4 using Interrupt SMI# for SMBus.\n");
187  else 
188     printk("piix4.o: PIIX4: Illegal Interrupt configuration (or code out "
189            "of date)!\n");
190
191  pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn, SMBREV, 
192                              &temp);
193  printk("piix4.o: SMBREV = 0x%X\n",temp);
194  printk("piix4.o: PIIX4_smba = 0x%X\n",piix4_smba);
195#endif /* DEBUG */
196
197END:
198  return error_return;
199}
200
201
202/* Internally used pause function */
203void piix4_do_pause( unsigned int amount )
204{
205      current->state = TASK_INTERRUPTIBLE;
206      schedule_timeout(amount);
207}
208
209/* Another internally used function */
210int piix4_transaction(void) 
211{
212  int temp;
213  int result=0;
214  int timeout=0;
215
216#ifdef DEBUG
217  printk("piix4.o: Transaction: CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
218         "DAT1=%02x\n",
219         inb_p(SMBHSTCNT),inb_p(SMBHSTCMD),inb_p(SMBHSTADD),inb_p(SMBHSTDAT0),
220         inb_p(SMBHSTDAT1));
221#endif
222
223  /* Make sure the SMBus host is ready to start transmitting */
224  if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
225#ifdef DEBUG
226    printk("piix4.o: SMBus busy (%02x). Resetting... \n",temp);
227#endif
228    outb_p(temp, SMBHSTSTS);
229    if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
230#ifdef DEBUG
231      printk("piix4.o: Failed! (%02x)\n",temp);
232#endif
233      return -1;
234    } else {
235#ifdef DEBUG
236      printk("piix4.o: Successfull!\n");
237#endif
238    }
239  }
240
241  /* start the transaction by setting bit 6 */
242  outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT); 
243
244  /* We will always wait for a fraction of a second! (See PIIX4 docs errata) */
245  do {
246    piix4_do_pause(1);
247    temp=inb_p(SMBHSTSTS);
248  } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
249
250  /* If the SMBus is still busy, we give up */
251  if (timeout >= MAX_TIMEOUT) {
252#ifdef DEBUG
253    printk("piix4.o: SMBus Timeout!\n"); 
254    result = -1;
255#endif
256  }
257
258  if (temp & 0x10) {
259    result = -1;
260#ifdef DEBUG
261    printk("piix4.o: Error: Failed bus transaction\n");
262#endif
263  }
264
265  if (temp & 0x08) {
266    result = -1;
267    printk("piix4.o: Bus collision! SMBus may be locked until next hard
268           reset. (sorry!)\n");
269    /* Clock stops and slave is stuck in mid-transmission */
270  }
271
272  if (temp & 0x04) {
273    result = -1;
274#ifdef DEBUG
275    printk("piix4.o: Error: no response!\n");
276#endif
277  }
278
279  if (inb_p(SMBHSTSTS) != 0x00)
280    outb_p( inb(SMBHSTSTS), SMBHSTSTS);
281
282  if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
283#ifdef DEBUG
284    printk("piix4.o: Failed reset at end of transaction (%02x)\n",temp);
285#endif
286  }
287  return result;
288}
289
290/* Return -1 on error. See smbus.h for more information */
291s32 piix4_access(u8 addr, char read_write,
292                 u8 command, int size, union smbus_data * data)
293{
294  int i,len;
295
296  switch(size) {
297    case SMBUS_PROC_CALL:
298      printk("piix4.o: SMBUS_PROC_CALL not supported!\n");
299      return -1;
300    case SMBUS_QUICK:
301      outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD);
302      size = PIIX4_QUICK;
303      break;
304    case SMBUS_BYTE:
305      outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD);
306      if (read_write == SMBUS_WRITE)
307        outb_p(command, SMBHSTCMD);
308      size = PIIX4_BYTE;
309      break;
310    case SMBUS_BYTE_DATA:
311      outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD);
312      outb_p(command, SMBHSTCMD);
313      if (read_write == SMBUS_WRITE)
314        outb_p(data->byte,SMBHSTDAT0);
315      size = PIIX4_BYTE_DATA;
316      break;
317    case SMBUS_WORD_DATA:
318      outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD);
319      outb_p(command, SMBHSTCMD);
320      if (read_write == SMBUS_WRITE) {
321        outb_p(data->word & 0xff,SMBHSTDAT0);
322        outb_p((data->word & 0xff00) >> 8,SMBHSTDAT1);
323      }
324      size = PIIX4_WORD_DATA;
325      break;
326    case SMBUS_BLOCK_DATA:
327      outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD);
328      outb_p(command, SMBHSTCMD);
329      if (read_write == SMBUS_WRITE) {
330        len = data->block[0];
331        if (len < 0) 
332          len = 0;
333        if (len > 32)
334          len = 32;
335        outb_p(len,SMBHSTDAT0);
336        i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
337        for (i = 1; i <= len; i ++)
338          outb_p(data->block[i],SMBBLKDAT);
339      }
340      size = PIIX4_BLOCK_DATA;
341      break;
342  }
343
344  outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
345
346  if (piix4_transaction()) /* Error in transaction */ 
347    return -1; 
348 
349  if ((read_write == SMBUS_WRITE) || (size == PIIX4_QUICK))
350    return 0;
351 
352
353  switch(size) {
354    case PIIX4_BYTE: /* Where is the result put? I assume here it is in
355                        SMBHSTDAT0 but it might just as well be in the
356                        SMBHSTCMD. No clue in the docs */
357 
358      data->byte = inb_p(SMBHSTDAT0);
359      break;
360    case PIIX4_BYTE_DATA:
361      data->byte = inb_p(SMBHSTDAT0);
362      break;
363    case PIIX4_WORD_DATA:
364      data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
365      break;
366    case PIIX4_BLOCK_DATA:
367      data->block[0] = inb_p(SMBHSTDAT0);
368      i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
369      for (i = 1; i <= data->block[0]; i++)
370        data->block[i] = inb_p(SMBBLKDAT);
371      break;
372  }
373  return 0;
374}
375
376
377int piix4_init(void)
378{
379  int res;
380  printk("piix4.o version %s (%s)\n",LM_VERSION,LM_DATE);
381#ifdef DEBUG
382/* PE- It might be good to make this a permanent part of the code! */
383  if (piix4_initialized) {
384    printk("piix4.o: Oops, piix4_init called a second time!\n");
385    return -EBUSY;
386  }
387#endif
388  piix4_initialized = 0;
389  if ((res = piix4_setup())) {
390    printk("piix4.o: PIIX4 not detected, module not inserted.\n");
391    piix4_cleanup();
392    return res;
393  }
394  piix4_initialized ++;
395  sprintf(piix4_adapter.name,"SMBus PIIX4 adapter at %04x",piix4_smba);
396  piix4_adapter.id = ALGO_SMBUS | SMBUS_PIIX4;
397  piix4_adapter.algo = &smbus_algorithm;
398  piix4_adapter.smbus_access = &piix4_access;
399  if ((res = smbus_add_adapter(&piix4_adapter))) {
400    printk("piix4.o: Adapter registration failed, module not inserted.\n");
401    piix4_cleanup();
402    return res;
403  }
404  piix4_initialized++;
405  printk("piix4.o: PIIX4 bus detected and initialized\n");
406  return 0;
407}
408
409int piix4_cleanup(void)
410{
411  int res;
412  if (piix4_initialized >= 2)
413  {
414    if ((res = smbus_del_adapter(&piix4_adapter))) {
415      printk("piix4.o: smbus_del_adapter failed, module not removed\n");
416      return res;
417    } else
418      piix4_initialized--;
419  }
420  if (piix4_initialized >= 1) {
421    release_region(piix4_smba, 8);
422    piix4_initialized--;
423  }
424  return 0;
425}
426
427#ifdef MODULE
428
429MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
430MODULE_DESCRIPTION("PIIX4 SMBus driver");
431
432int init_module(void)
433{
434  return piix4_init();
435}
436
437int cleanup_module(void)
438{
439  return piix4_cleanup();
440}
441
442#endif /* MODULE */
443
Note: See TracBrowser for help on using the browser.