root/lm-sensors/trunk/prog/hotplug/p4b_smbus.c @ 2459

Revision 2459, 8.2 KB (checked in by khali, 11 years ago)

(Axel Thimm) Support 82801BAM and 82801DBM.

Some fixes and cleanups.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * p4b_smbus.c
3 *
4 * Initialize the SMBus device on ICH2/2-M/4/4-M (82801BA/BAM/DB/DBM)
5 */
6/*
7    Copyright (c) 2002 Ilja Rauhut <IljaRauhut@web.de> and
8    Klaus Woltereck <kw42@gmx.net>,
9
10    Based on the m7101.c hotplug example by:
11
12    Copyright (c) 2000 Burkhard Kohl <buk@buks.ipn.de>,
13    Frank Bauer <frank.bauer@nikocity.de>, and
14    Mark D. Studebaker <mdsxyz123@yahoo.com>
15
16    This program is free software; you can redistribute it and/or modify
17    it under the terms of the GNU General Public License as published by
18    the Free Software Foundation; either version 2 of the License, or
19    (at your option) any later version.
20
21    This program is distributed in the hope that it will be useful,
22    but WITHOUT ANY WARRANTY; without even the implied warranty of
23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24    GNU General Public License for more details.
25
26    You should have received a copy of the GNU General Public License
27    along with this program; if not, write to the Free Software
28    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 */
30/* CHANGES:
31 * February 13,2002 IR First Version
32 *
33 * This code is absolutely experimental - use it at your own
34 * risk.
35 *
36 * Warning, this module will work only with 2.4.x kernels.
37 * If it works with earlier kernels then it is by luck.
38 *
39 * Warning, this module does not work with egcs < 2.95.2, use
40 * gcc > 2.7.2 or egcs >= 2.95.2.
41 *
42 *
43 * June 21, 2002, added support for the ICH4, code clean up -- Klaus
44 *
45 * Apr 13, 2004, modified for ICH4-M (82801DBM) -- Axel Thimm <Axel.Thimm@ATrpms.net>
46 *               bugfix: register F2/bit 8 on ICH2* is bit 0 on ICH4*
47 */
48
49
50#ifdef P4Bsmbus_DEBUG
51#define DBG(x...) printk(x)
52#else
53#define DBG(x...)
54#endif
55
56#ifndef TRUE
57#define TRUE 1
58#define FALSE !TRUE
59#endif
60
61#include <linux/config.h>
62#ifndef CONFIG_HOTPLUG
63#error ERROR - You must have 'Support for hot-pluggable devices' enabled in your kernel (under 'general setup')!!
64#endif
65
66#include <linux/module.h>
67#include <linux/kernel.h>
68#include <linux/pci.h>
69#include <linux/stddef.h>
70#include <linux/ioport.h>
71#include <linux/errno.h>
72#include <linux/slab.h>
73#include <linux/interrupt.h>
74#include <asm/types.h>
75
76#include <linux/sched.h>
77#include <linux/signal.h>
78#include <asm/irq.h>
79
80/*
81rmm    from lm_sensors-2.3.3:
82 */
83
84#define SMB_IO_SIZE  0xF
85#define SMB_BASE 0x20
86
87
88/*
89 * some shorter definitions for the ICHx PCI device IDs
90 */
91
92#define ICH2 0x2440
93#define ICH2_M 0x244c
94#define ICH2_SMBUS 0x2443
95
96#define ICH4 0x24c0
97#define ICH4_M 0x24cc
98#define ICH4_SMBUS 0x24c3
99
100/* status, used to indicate that io space needs to be freed */
101static struct pci_dev *i801smbus = NULL;
102static int i801smbus_inserted = FALSE;
103extern void cleanup_module(void);
104 
105static rwlock_t i801smbus_lock = RW_LOCK_UNLOCKED;
106static unsigned long i801smbus_lock_flags = 0;
107
108/*
109 * Checks whether SMBus is enabled and turns it on in case they are not.
110 * It's done by modifying the i801 function disable register, F2h.
111 * ICH2(-M): PCI-Device 0x8086:0x2440(0x244c)
112 *           Bit 3: Disables SMBus Host Controller function.
113 *           Bit 8: allows SMBus I/O space to be accessible when Bit 3 is set.
114 * ICH4(-M): PCI-Device 0x8086:0x24c0(0x24cc)
115 *           Bit 3: Disables SMBus Host Controller function.
116 *           Bit 0: allows SMBus I/O space to be accessible when Bit 3 is set.
117 */
118static int
119i801smbus_enable(struct pci_dev *dev, u16 testmask, u16 mask){
120        u16  val   = 0;
121
122        pci_read_config_word(dev, 0xF2, &val);
123        DBG("i801smbus: i801smbus config byte reading 0x%X.\n", val);
124        if (val & testmask) {
125                pci_write_config_word(dev, 0xF2, val & mask);
126                pci_read_config_word(dev, 0xF2, &val);
127                if(val & testmask) 
128                  {
129                    DBG("i801smbus: i801smbus config byte locked:-(\n");
130                    return -EIO;
131                  }
132                else
133                  printk("i801smbus: SMBus activated in LPC!\n");
134        }
135        return 0;
136
137}
138
139/*
140 * Builds the basic pci_dev for the i801smbus
141 */
142static int i801smbus_build(struct pci_dev **i801smbus, struct pci_bus *bus) 
143{
144        u32 devfn;
145        u16 id = 0;
146        u16 vid = 0;
147        int ret;
148
149        DBG("i801smbus: requesting kernel space for the i801smbus entry.\n");
150        *i801smbus = kmalloc(sizeof(**i801smbus), GFP_ATOMIC);
151        if(NULL == *i801smbus) {
152                printk("i801smbus: out of memory.\n");
153                return -ENOMEM;
154        }
155
156        /* minimally fill in structure for search */
157        /* The device should be on the same bus as the i801. */
158        memset(*i801smbus, 0, sizeof(**i801smbus));
159        (*i801smbus)->bus    = bus;
160        (*i801smbus)->sysdata = bus->sysdata;
161        (*i801smbus)->hdr_type = PCI_HEADER_TYPE_NORMAL;
162
163        DBG("i801smbus: now looking for i801smbus.\n");
164        for  (id = 0, devfn = 0; devfn < 0xFF; devfn++) {
165                (*i801smbus)->devfn = devfn;
166                ret = pci_read_config_word(*i801smbus, PCI_DEVICE_ID, &id);
167                if (ret == 0 && (ICH2_SMBUS == id || ICH4_SMBUS == id)) {
168                        pci_read_config_word(*i801smbus, PCI_VENDOR_ID, &vid);
169                        if(vid == 0x8086)
170                                break;
171                }
172        }
173        if (!(ICH2_SMBUS == id || ICH4_SMBUS == id)) { 
174                DBG("i801smbus: i801smbus not found although i801 present - strange.\n");
175                return -EACCES;
176        } else {
177                DBG("i801smbus: i801smbus found and enabled. Devfn: 0x%X.\n", devfn);
178        }
179        /* We now have the devfn and bus of the i801smbus device.
180         * let's put the rest of the device data together.
181         */
182
183        (*i801smbus)->vendor = 0x8086;
184        (*i801smbus)->hdr_type = PCI_HEADER_TYPE_NORMAL;
185        (*i801smbus)->device = id;
186 
187        return(pci_setup_device(*i801smbus));
188}
189
190
191
192
193/* Initialize the module */
194int init_module(void)
195{
196        struct pci_bus *bus = NULL;
197        struct pci_dev *dev = NULL;
198        int ret = 0;
199        u16 testmask = 0, mask = 0;
200
201        DBG("i801smbus: init_module().\n");
202
203        /* Are we on a PCI-Board? */
204        if (!pci_present()) {
205                printk("i801smbus: No PCI bus found - sorry.\n");
206                return -ENODEV;
207        }
208
209        /* We want to be sure that the i801smbus is not present yet. */
210        dev = pci_find_device(0x8086, ICH2_SMBUS, NULL);
211
212        if (dev) 
213          {
214            printk("i801smbus: SMBus already active\n");
215            return -EPERM;
216          }
217       
218        dev = pci_find_device(0x8086, ICH4_SMBUS, NULL);
219
220        if (dev) 
221          {
222            printk("i801smbus: SMBus already active\n");
223            return -EPERM;
224          }
225       
226        /* Are we operating a i801 chipset */
227        if ((dev = pci_find_device(0x8086, ICH2, NULL)) != 0)
228          {
229            printk("i801smbus: found Intel ICH2 (82801BA).\n");
230            testmask = 0x008;
231            mask = 0xfef7;
232          }
233        else if ((dev = pci_find_device(0x8086, ICH2_M, NULL)) != 0)
234          {
235            printk("i801smbus: found Intel ICH2-M (82801BAM).\n");
236            testmask = 0x008;
237            mask = 0xfef7;
238          }
239        else if ((dev = pci_find_device(0x8086, ICH4, NULL)) != 0)
240          {
241            printk("i801smbus: found Intel ICH4 (82801DB).\n");
242            testmask = 0x008;
243            mask = 0xfff6;
244          }
245        else if ((dev = pci_find_device(0x8086, ICH4_M, NULL)) != 0)
246          {
247            printk("i801smbus: found Intel ICH4-M (82801DBM).\n");
248            testmask = 0x008;
249            mask = 0xfff6;
250          }
251        else
252          {
253            printk("i801smbus: INTEL ICH2/2-M/4/4-M (82801BA/BAM/DB/DBM) not found.\n");
254            return -ENODEV ;
255          }
256
257        /* we need the bus pointer later */
258        bus = dev->bus;
259
260
261        if ( (ret = i801smbus_enable(dev, testmask, mask)) ) 
262          {
263            printk("i801smbus: Unable to turn on i801smbus device - sorry!\n");
264            return ret;
265          }
266     
267        if ( (ret = i801smbus_build(&i801smbus, bus)) )
268                return ret;
269
270
271        if ( (ret = pci_enable_device(i801smbus)) ) {
272                printk("i801smbus: Unable to pci_enable i801smbus device!\n");
273                return ret;
274        }
275   
276        DBG("i801smbus: now inserting.\n");
277        pci_insert_device(i801smbus, i801smbus->bus);
278        printk("i801smbus: Enabled\n");
279        i801smbus_inserted = TRUE;
280        return 0;
281}
282
283
284void cleanup_module(void)
285{
286        write_lock_irqsave(&i801smbus_lock, i801smbus_lock_flags);
287        if (i801smbus_inserted) {
288                pci_remove_device(i801smbus);
289                i801smbus_inserted = FALSE;
290        }
291        write_unlock_irqrestore(&i801smbus_lock, i801smbus_lock_flags);
292
293        if (NULL != i801smbus)
294          {
295            kfree(i801smbus);
296          }
297        printk("i801smbus: SMBus device removed\n");
298}
299
300EXPORT_NO_SYMBOLS;
301
302#ifdef MODULE
303#ifdef MODULE_LICENSE
304MODULE_LICENSE("GPL");
305#endif
306MODULE_AUTHOR("Ilja Rauhut <IljaRauhut@web.de>, "
307              "Burkhard Kohl <bku@buks.ipn.de>, "
308              "Frank Bauer <frank.bauer@nikocity.de>, "
309              "Mark Studebaker <mdsxyz123@yahoo.com>,"
310              "and Klaus Woltereck <kw42@gmx.net>");
311MODULE_DESCRIPTION("i801smbus PCI Inserter");
312
313#endif                          /* MODULE */
314
315
316
317
318
319
320
321
322
323
Note: See TracBrowser for help on using the browser.