root/lm-sensors/trunk/kernel/busses/i2c-sis645.c @ 3149

Revision 3149, 15.0 KB (checked in by khali, 8 years ago)

Backport from Linux 2.6:

Clean up name string usage in 11 i2c bus drivers:
* Use the pci_driver name for requesting the I/O region rather than

redefining a new string.

* Do not initialize the i2c_adapter name to "unset".
This should save a few data bytes here and there.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    sis645.c - Part of lm_sensors, Linux kernel modules for hardware
3              monitoring
4
5    Copyright (c) 2003 Mark M. Hoffman <mhoffman@lightlink.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/*
23    This module must be considered BETA unless and until
24    the chipset manufacturer releases a datasheet.
25
26    The register definitions are based on the SiS630.
27    The method for *finding* the registers is based on trial and error.
28
29    A history of changes to this file is available by anonymous CVS:
30    http://www2.lm-sensors.nu/~lm78/download.html
31*/
32
33/*   25th March 2004
34     Support for Sis655 chipsets added by Ken Healy
35*/
36
37/*
38    Note: we assume there can only be one SiS645 with one SMBus interface
39*/
40
41/* #define DEBUG 1 */
42
43#include <linux/module.h>
44#include <linux/pci.h>
45#include <linux/kernel.h>
46#include <linux/stddef.h>
47#include <linux/sched.h>
48#include <linux/ioport.h>
49#include <linux/i2c.h>
50#include <linux/init.h>
51#include <linux/mm.h>
52#include <asm/io.h>
53#include "version.h"
54#include "sensors_compat.h"
55
56#define DRV_NAME "i2c-sis645"
57
58/* SiS645DX north bridge (defined in 2.4.21) */
59#ifndef PCI_DEVICE_ID_SI_646
60#define PCI_DEVICE_ID_SI_646 0x0646
61#endif
62
63/* SiS648 north bridge (defined in 2.4.21) */
64#ifndef PCI_DEVICE_ID_SI_648
65#define PCI_DEVICE_ID_SI_648 0x0648
66#endif
67
68/* SiS650 north bridge (defined in 2.4.19) */
69#ifndef PCI_DEVICE_ID_SI_650
70#define PCI_DEVICE_ID_SI_650 0x0650
71#endif
72
73/* SiS651 north bridge (defined in 2.4.21)*/
74#ifndef PCI_DEVICE_ID_SI_651
75#define PCI_DEVICE_ID_SI_651 0x0651
76#endif
77
78/* SiS655 north bridge (defined in 2.4.22)*/
79#ifndef PCI_DEVICE_ID_SI_655
80#define PCI_DEVICE_ID_SI_655 0x0655
81#endif
82
83/* SiS746 north bridge (defined in 2.4.21) */
84#ifndef PCI_DEVICE_ID_SI_746
85#define PCI_DEVICE_ID_SI_746 0x0746
86#endif
87
88/* SiS85C503/5513 (LPC Bridge) */
89#ifndef PCI_DEVICE_ID_SI_LPC
90#define PCI_DEVICE_ID_SI_LPC 0x0018
91#endif
92
93/* SiS961 south bridge */
94#ifndef PCI_DEVICE_ID_SI_961
95#define PCI_DEVICE_ID_SI_961 0x0961
96#endif
97
98/* SiS962 south bridge */
99#ifndef PCI_DEVICE_ID_SI_962
100#define PCI_DEVICE_ID_SI_962 0x0962
101#endif
102
103/* SiS963 south bridge */
104#ifndef PCI_DEVICE_ID_SI_963
105#define PCI_DEVICE_ID_SI_963 0x0963
106#endif
107
108/* SMBus ID */
109#ifndef PCI_DEVICE_ID_SI_SMBUS
110#define PCI_DEVICE_ID_SI_SMBUS 0x16
111#endif
112
113/* base address register in PCI config space */
114#define SIS645_BAR 0x04
115
116/* SiS645 SMBus registers */
117#define SMB_STS      0x00
118#define SMB_EN       0x01
119#define SMB_CNT      0x02
120#define SMB_HOST_CNT 0x03
121#define SMB_ADDR     0x04
122#define SMB_CMD      0x05
123#define SMB_PCOUNT   0x06
124#define SMB_COUNT    0x07
125#define SMB_BYTE     0x08
126#define SMB_DEV_ADDR 0x10
127#define SMB_DB0      0x11
128#define SMB_DB1      0x12
129#define SMB_SAA      0x13
130
131/* register count for request_region */
132#define SMB_IOSIZE 0x20
133
134/* Other settings */
135#define MAX_TIMEOUT 500
136
137/* SiS645 SMBus constants */
138#define SIS645_QUICK      0x00
139#define SIS645_BYTE       0x01
140#define SIS645_BYTE_DATA  0x02
141#define SIS645_WORD_DATA  0x03
142#define SIS645_PROC_CALL  0x04
143#define SIS645_BLOCK_DATA 0x05
144
145static struct pci_driver sis645_driver;
146static struct i2c_adapter sis645_adapter;
147static u16 sis645_smbus_base = 0;
148
149static inline u8 sis645_read(u8 reg)
150{
151        return inb(sis645_smbus_base + reg) ;
152}
153
154static inline void sis645_write(u8 reg, u8 data)
155{
156        outb(data, sis645_smbus_base + reg) ;
157}
158
159#ifdef CONFIG_HOTPLUG
160
161/* Turns on SMBus device if it is not; return 0 iff successful
162 */
163static int __devinit sis645_enable_smbus(struct pci_dev *dev)
164{
165        u8 val = 0;
166
167        pci_read_config_byte(dev, 0x77, &val);
168
169#ifdef DEBUG
170        printk(KERN_DEBUG DRV_NAME ": Config byte was 0x%02x.\n", val);
171#endif
172
173        pci_write_config_byte(dev, 0x77, val & ~0x10);
174
175        pci_read_config_byte(dev, 0x77, &val);
176
177        if (val & 0x10) {
178#ifdef DEBUG
179                printk(KERN_DEBUG DRV_NAME ": Config byte stuck!\n");
180#endif
181                return -1;
182        }
183
184        return 0;
185}
186
187/* Builds the basic pci_dev for SiS645 SMBus
188 */
189static int __devinit sis645_build_dev(struct pci_dev **smbus_dev,
190                            struct pci_dev *bridge_dev)
191{
192        struct pci_dev temp_dev;
193        u16 vid = 0, did = 0;
194        int ret;
195
196        /* fill in the device structure for search */
197        memset(&temp_dev, 0, sizeof(temp_dev));
198        temp_dev.bus = bridge_dev->bus;
199        temp_dev.sysdata = bridge_dev->bus->sysdata;
200        temp_dev.hdr_type = PCI_HEADER_TYPE_NORMAL;
201
202        /* the SMBus device is function 1 on the same unit as the ISA bridge */
203        temp_dev.devfn = bridge_dev->devfn + 1;
204
205        /* query to make sure */
206        ret = pci_read_config_word(&temp_dev, PCI_VENDOR_ID, &vid);
207        if (ret || PCI_VENDOR_ID_SI != vid) {
208                printk(KERN_ERR DRV_NAME ": Couldn't find SMBus device!\n");
209                return ret;
210        }
211        temp_dev.vendor = vid;
212
213        ret = pci_read_config_word(&temp_dev, PCI_DEVICE_ID, &did);
214        if (ret || PCI_DEVICE_ID_SI_SMBUS != did) {
215                printk(KERN_ERR DRV_NAME ": Couldn't find SMBus device!\n");
216                return ret;
217        }
218        temp_dev.device = did;
219
220        /* ok, we've got it... request some memory and finish it off */
221        *smbus_dev = kmalloc(sizeof(**smbus_dev), GFP_ATOMIC);
222        if (NULL == *smbus_dev) {
223                printk(KERN_ERR DRV_NAME ": Out of memory!\n");
224                return -ENOMEM;
225        }
226
227        **smbus_dev = temp_dev;
228       
229        ret = pci_setup_device(*smbus_dev);
230        if (ret) {
231                printk(KERN_ERR DRV_NAME ": pci_setup_device failed (0x%08x)\n",ret);
232        }
233        return ret;
234}
235
236/* See if a SMBus can be found, and enable it if possible.
237 */
238static int __devinit sis645_hotplug_smbus(void)
239{
240        int ret;
241        struct pci_dev *smbus_dev, *bridge_dev ;
242
243        if ((bridge_dev = pci_find_device(PCI_VENDOR_ID_SI,
244                        PCI_DEVICE_ID_SI_961, NULL)))
245                printk(KERN_INFO DRV_NAME ": Found SiS961 south bridge.\n");
246
247        else if ((bridge_dev = pci_find_device(PCI_VENDOR_ID_SI,
248                        PCI_DEVICE_ID_SI_962, NULL)))
249                printk(KERN_INFO DRV_NAME ": Found SiS962 [MuTIOL Media IO].\n");
250
251        else if ((bridge_dev = pci_find_device(PCI_VENDOR_ID_SI,
252                        PCI_DEVICE_ID_SI_963, NULL)))
253                printk(KERN_INFO DRV_NAME ": Found SiS963 [MuTIOL Media IO].\n");
254               
255        else if ((bridge_dev = pci_find_device(PCI_VENDOR_ID_SI,
256                        PCI_DEVICE_ID_SI_503, NULL)) ||
257                (bridge_dev = pci_find_device(PCI_VENDOR_ID_SI,
258                        PCI_DEVICE_ID_SI_LPC, NULL))) {
259
260                printk(KERN_INFO DRV_NAME ": Found SiS south bridge in compatability mode(?)\n");
261
262                /* look for known compatible north bridges */
263                if ((NULL == pci_find_device(PCI_VENDOR_ID_SI, 
264                                PCI_DEVICE_ID_SI_645, NULL))
265                        && (NULL == pci_find_device(PCI_VENDOR_ID_SI,
266                                PCI_DEVICE_ID_SI_646, NULL))
267                        && (NULL == pci_find_device(PCI_VENDOR_ID_SI,
268                                PCI_DEVICE_ID_SI_648, NULL))
269                        && (NULL == pci_find_device(PCI_VENDOR_ID_SI,
270                                PCI_DEVICE_ID_SI_650, NULL))
271                        && (NULL == pci_find_device(PCI_VENDOR_ID_SI,
272                                PCI_DEVICE_ID_SI_651, NULL))
273                        && (NULL == pci_find_device(PCI_VENDOR_ID_SI,
274                                PCI_DEVICE_ID_SI_655, NULL))
275                        && (NULL == pci_find_device(PCI_VENDOR_ID_SI,
276                                PCI_DEVICE_ID_SI_735, NULL))
277                        && (NULL == pci_find_device(PCI_VENDOR_ID_SI,
278                                PCI_DEVICE_ID_SI_745, NULL))
279                        && (NULL == pci_find_device(PCI_VENDOR_ID_SI,
280                                PCI_DEVICE_ID_SI_746, NULL))) {
281                        printk(KERN_ERR DRV_NAME ": Can't find suitable host bridge!\n");
282                        return -ENODEV;
283                }
284        } else {
285                printk(KERN_ERR DRV_NAME ": Can't find suitable south bridge!\n");
286                return -ENODEV;
287        }
288
289        /* if we get this far, we think the smbus device is present */
290
291        if ((ret = sis645_enable_smbus(bridge_dev)))
292                return ret;
293
294        if ((ret = sis645_build_dev(&smbus_dev, bridge_dev)))
295                return ret;
296
297        if ((ret = pci_enable_device(smbus_dev))) {
298                printk(KERN_ERR DRV_NAME ": Can't pci_enable SMBus device!"
299                        " (0x%08x)\n", ret);
300                return ret;
301        }
302
303        pci_insert_device(smbus_dev, smbus_dev->bus);
304
305        return 0;
306}
307#endif /* CONFIG_HOTPLUG */
308
309/* Execute a SMBus transaction.
310   int size is from SIS645_QUICK to SIS645_BLOCK_DATA
311 */
312static int sis645_transaction(int size)
313{
314        int temp;
315        int result = 0;
316        int timeout = 0;
317
318        /* Make sure the SMBus host is ready to start transmitting */
319        if (((temp = sis645_read(SMB_CNT)) & 0x03) != 0x00) {
320#ifdef DEBUG
321                printk(KERN_DEBUG DRV_NAME ": SMBus busy (0x%02x). Resetting...\n",
322                                temp);
323#endif
324
325                /* kill the transaction */
326                sis645_write(SMB_HOST_CNT, 0x20);
327
328                /* check it again */
329                if (((temp = sis645_read(SMB_CNT)) & 0x03) != 0x00) {
330#ifdef DEBUG
331                        printk(KERN_DEBUG DRV_NAME ": Failed! (0x%02x)\n", temp);
332#endif
333                        return -1;
334                } else {
335#ifdef DEBUG
336                        printk(KERN_DEBUG DRV_NAME ": Successful!\n");
337#endif
338                }
339        }
340
341        /* Turn off timeout interrupts, set fast host clock */
342        sis645_write(SMB_CNT, 0x20);
343
344        /* clear all (sticky) status flags */
345        temp = sis645_read(SMB_STS);
346        sis645_write(SMB_STS, temp & 0x1e);
347
348        /* start the transaction by setting bit 4 and size bits */
349        sis645_write(SMB_HOST_CNT, 0x10 | (size & 0x07));
350
351        /* We will always wait for a fraction of a second! */
352        do {
353                i2c_delay(1);
354                temp = sis645_read(SMB_STS);
355        } while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT));
356
357        /* If the SMBus is still busy, we give up */
358        if (timeout >= MAX_TIMEOUT) {
359                printk(KERN_DEBUG DRV_NAME ": SMBus Timeout! (0x%02x)\n",temp);
360                result = -1;
361        }
362
363        /* device error - probably missing ACK */
364        if (temp & 0x02) {
365#ifdef DEBUG
366                printk(KERN_DEBUG DRV_NAME ": Failed bus transaction!\n");
367#endif
368                result = -1;
369        }
370
371        /* bus collision */
372        if (temp & 0x04) {
373#ifdef DEBUG
374                printk(KERN_DEBUG DRV_NAME ": Bus collision!\n");
375#endif
376                result = -1;
377        }
378
379        /* Finish up by resetting the bus */
380        sis645_write(SMB_STS, temp);
381        if ((temp = sis645_read(SMB_STS))) {
382#ifdef DEBUG
383                printk(KERN_DEBUG DRV_NAME ": Failed reset at end of transaction!"
384                                " (0x%02x)\n", temp);
385#endif
386        }
387
388        return result;
389}
390
391/* Return -1 on error. */
392static s32 sis645_access(struct i2c_adapter * adap, u16 addr,
393                   unsigned short flags, char read_write,
394                   u8 command, int size, union i2c_smbus_data * data)
395{
396
397        switch (size) {
398        case I2C_SMBUS_QUICK:
399                sis645_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
400                size = SIS645_QUICK;
401                break;
402
403        case I2C_SMBUS_BYTE:
404                sis645_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
405                if (read_write == I2C_SMBUS_WRITE)
406                        sis645_write(SMB_CMD, command);
407                size = SIS645_BYTE;
408                break;
409
410        case I2C_SMBUS_BYTE_DATA:
411                sis645_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
412                sis645_write(SMB_CMD, command);
413                if (read_write == I2C_SMBUS_WRITE)
414                        sis645_write(SMB_BYTE, data->byte);
415                size = SIS645_BYTE_DATA;
416                break;
417
418        case I2C_SMBUS_PROC_CALL:
419        case I2C_SMBUS_WORD_DATA:
420                sis645_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
421                sis645_write(SMB_CMD, command);
422                if (read_write == I2C_SMBUS_WRITE) {
423                        sis645_write(SMB_BYTE, data->word & 0xff);
424                        sis645_write(SMB_BYTE + 1, (data->word & 0xff00) >> 8);
425                }
426                size = (size == I2C_SMBUS_PROC_CALL ? SIS645_PROC_CALL : SIS645_WORD_DATA);
427                break;
428
429        case I2C_SMBUS_BLOCK_DATA:
430                /* TO DO: */
431                printk(KERN_INFO DRV_NAME ": SMBus block not implemented!\n");
432                return -1;
433                break;
434
435        default:
436                printk(KERN_INFO DRV_NAME ": Unsupported I2C size\n");
437                return -1;
438                break;
439        }
440
441        if (sis645_transaction(size))
442                return -1;
443
444        if ((size != SIS645_PROC_CALL) &&
445                        ((read_write == I2C_SMBUS_WRITE) || (size == SIS645_QUICK)))
446                return 0;
447
448        switch (size) {
449        case SIS645_BYTE:
450        case SIS645_BYTE_DATA:
451                data->byte = sis645_read(SMB_BYTE);
452                break;
453
454        case SIS645_WORD_DATA:
455        case SIS645_PROC_CALL:
456                data->word = sis645_read(SMB_BYTE) +
457                                (sis645_read(SMB_BYTE + 1) << 8);
458                break;
459        }
460        return 0;
461}
462
463static void sis645_inc(struct i2c_adapter *adapter)
464{
465#ifdef MODULE
466        MOD_INC_USE_COUNT;
467#endif
468}
469
470static void sis645_dec(struct i2c_adapter *adapter)
471{
472#ifdef MODULE
473        MOD_DEC_USE_COUNT;
474#endif
475}
476
477static u32 sis645_func(struct i2c_adapter *adapter)
478{
479        return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
480            I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
481            I2C_FUNC_SMBUS_PROC_CALL;
482}
483
484static struct i2c_algorithm smbus_algorithm = {
485        .name           = "Non-I2C SMBus adapter",
486        .id             = I2C_ALGO_SMBUS,
487        .smbus_xfer     = sis645_access,
488        .functionality  = sis645_func,
489};
490
491static struct i2c_adapter sis645_adapter = {
492        .id             = I2C_ALGO_SMBUS | I2C_HW_SMBUS_SIS645,
493        .algo           = &smbus_algorithm,
494        .inc_use        = sis645_inc,
495        .dec_use        = sis645_dec,
496};
497
498static struct pci_device_id sis645_ids[] __devinitdata = {
499        {
500                .vendor = PCI_VENDOR_ID_SI,
501                .device = PCI_DEVICE_ID_SI_SMBUS,
502                .subvendor = PCI_ANY_ID,
503                .subdevice = PCI_ANY_ID,
504        },
505        { 0, }
506};
507
508static int __devinit sis645_probe(struct pci_dev *dev,
509                                const struct pci_device_id *id)
510{
511        u16 ww = 0;
512        int retval;
513
514        if (sis645_smbus_base) {
515                dev_err(dev, "Only one device supported.\n");
516                return -EBUSY;
517        }
518
519        pci_read_config_word(dev, PCI_CLASS_DEVICE, &ww);
520        if (PCI_CLASS_SERIAL_SMBUS != ww) {
521                dev_err(dev, "Unsupported device class 0x%04x!\n", ww);
522                return -ENODEV;
523        }
524
525        sis645_smbus_base = pci_resource_start(dev, SIS645_BAR);
526        if (!sis645_smbus_base) {
527                dev_err(dev, "SiS645 SMBus base address "
528                        "not initialized!\n");
529                return -EINVAL;
530        }
531        dev_info(dev, "SiS645 SMBus base address: 0x%04x\n",
532                        sis645_smbus_base);
533
534        /* Everything is happy, let's grab the memory and set things up. */
535        if (!request_region(sis645_smbus_base, SMB_IOSIZE,
536                            sis645_driver.name)) {
537                dev_err(dev, "SMBus registers 0x%04x-0x%04x "
538                        "already in use!\n", sis645_smbus_base,
539                        sis645_smbus_base + SMB_IOSIZE - 1);
540
541                sis645_smbus_base = 0;
542                return -EINVAL;
543        }
544
545        sprintf(sis645_adapter.name, "SiS645 SMBus adapter at 0x%04x",
546                        sis645_smbus_base);
547
548        if ((retval = i2c_add_adapter(&sis645_adapter))) {
549                dev_err(dev, "Couldn't register adapter!\n");
550                release_region(sis645_smbus_base, SMB_IOSIZE);
551                sis645_smbus_base = 0;
552        }
553
554        return retval;
555}
556
557static void __devexit sis645_remove(struct pci_dev *dev)
558{
559        if (sis645_smbus_base) {
560                i2c_del_adapter(&sis645_adapter);
561                release_region(sis645_smbus_base, SMB_IOSIZE);
562                sis645_smbus_base = 0;
563        }
564}
565
566static struct pci_driver sis645_driver = {
567        .name           = "sis645 smbus",
568        .id_table       = sis645_ids,
569        .probe          = sis645_probe,
570        .remove         = __devexit_p(sis645_remove),
571};
572
573static int __init i2c_sis645_init(void)
574{
575        printk(KERN_INFO DRV_NAME ".o version %s (%s)\n", LM_VERSION, LM_DATE);
576
577        /* if the required device id is not present, try to HOTPLUG it first */
578        if (!pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS, NULL)) {
579
580                printk(KERN_INFO DRV_NAME ": "
581                        "Attempting to enable SiS645 SMBus device\n");
582
583#ifdef CONFIG_HOTPLUG
584                sis645_hotplug_smbus();
585#else
586                printk(KERN_INFO DRV_NAME ": "
587                        "Requires kernel with CONFIG_HOTPLUG, sorry!\n");
588#endif
589        }
590
591        return pci_module_init(&sis645_driver);
592}
593
594static void __exit i2c_sis645_exit(void)
595{
596        pci_unregister_driver(&sis645_driver);
597}
598
599MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
600MODULE_DESCRIPTION("SiS645 SMBus driver");
601MODULE_LICENSE("GPL");
602
603/* Register initialization functions using helper macros */
604module_init(i2c_sis645_init);
605module_exit(i2c_sis645_exit);
Note: See TracBrowser for help on using the browser.