linux/drivers/i2c/busses/i2c-sis5595.c
<<
>>
Prefs
   1/*
   2    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> and
   3    Philip Edelbrock <phil@netroedge.com>
   4
   5    This program is free software; you can redistribute it and/or modify
   6    it under the terms of the GNU General Public License as published by
   7    the Free Software Foundation; either version 2 of the License, or
   8    (at your option) any later version.
   9
  10    This program is distributed in the hope that it will be useful,
  11    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13    GNU General Public License for more details.
  14
  15    You should have received a copy of the GNU General Public License
  16    along with this program; if not, write to the Free Software
  17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18*/
  19
  20/* Note: we assume there can only be one SIS5595 with one SMBus interface */
  21
  22/*
  23   Note: all have mfr. ID 0x1039.
  24   SUPPORTED            PCI ID          
  25        5595            0008
  26
  27   Note: these chips contain a 0008 device which is incompatible with the
  28         5595. We recognize these by the presence of the listed
  29         "blacklist" PCI ID and refuse to load.
  30
  31   NOT SUPPORTED        PCI ID          BLACKLIST PCI ID        
  32         540            0008            0540
  33         550            0008            0550
  34        5513            0008            5511
  35        5581            0008            5597
  36        5582            0008            5597
  37        5597            0008            5597
  38        5598            0008            5597/5598
  39         630            0008            0630
  40         645            0008            0645
  41         646            0008            0646
  42         648            0008            0648
  43         650            0008            0650
  44         651            0008            0651
  45         730            0008            0730
  46         735            0008            0735
  47         745            0008            0745
  48         746            0008            0746
  49*/
  50
  51/* TO DO: 
  52 * Add Block Transfers (ugly, but supported by the adapter)
  53 * Add adapter resets
  54 */
  55
  56#include <linux/kernel.h>
  57#include <linux/module.h>
  58#include <linux/delay.h>
  59#include <linux/pci.h>
  60#include <linux/ioport.h>
  61#include <linux/init.h>
  62#include <linux/i2c.h>
  63#include <linux/acpi.h>
  64#include <linux/io.h>
  65
  66static int blacklist[] = {
  67        PCI_DEVICE_ID_SI_540,
  68        PCI_DEVICE_ID_SI_550,
  69        PCI_DEVICE_ID_SI_630,
  70        PCI_DEVICE_ID_SI_645,
  71        PCI_DEVICE_ID_SI_646,
  72        PCI_DEVICE_ID_SI_648,
  73        PCI_DEVICE_ID_SI_650,
  74        PCI_DEVICE_ID_SI_651,
  75        PCI_DEVICE_ID_SI_730,
  76        PCI_DEVICE_ID_SI_735,
  77        PCI_DEVICE_ID_SI_745,
  78        PCI_DEVICE_ID_SI_746,
  79        PCI_DEVICE_ID_SI_5511,  /* 5513 chip has the 0008 device but that ID
  80                                   shows up in other chips so we use the 5511
  81                                   ID for recognition */
  82        PCI_DEVICE_ID_SI_5597,
  83        PCI_DEVICE_ID_SI_5598,
  84        0,                      /* terminates the list */
  85};
  86
  87/* Length of ISA address segment */
  88#define SIS5595_EXTENT          8
  89/* SIS5595 SMBus registers */
  90#define SMB_STS_LO              0x00
  91#define SMB_STS_HI              0x01
  92#define SMB_CTL_LO              0x02
  93#define SMB_CTL_HI              0x03
  94#define SMB_ADDR                0x04
  95#define SMB_CMD                 0x05
  96#define SMB_PCNT                0x06
  97#define SMB_CNT                 0x07
  98#define SMB_BYTE                0x08
  99#define SMB_DEV                 0x10
 100#define SMB_DB0                 0x11
 101#define SMB_DB1                 0x12
 102#define SMB_HAA                 0x13
 103
 104/* PCI Address Constants */
 105#define SMB_INDEX               0x38
 106#define SMB_DAT                 0x39
 107#define SIS5595_ENABLE_REG      0x40
 108#define ACPI_BASE               0x90
 109
 110/* Other settings */
 111#define MAX_TIMEOUT             500
 112
 113/* SIS5595 constants */
 114#define SIS5595_QUICK           0x00
 115#define SIS5595_BYTE            0x02
 116#define SIS5595_BYTE_DATA       0x04
 117#define SIS5595_WORD_DATA       0x06
 118#define SIS5595_PROC_CALL       0x08
 119#define SIS5595_BLOCK_DATA      0x0A
 120
 121/* insmod parameters */
 122
 123/* If force_addr is set to anything different from 0, we forcibly enable
 124   the device at the given address. */
 125static u16 force_addr;
 126module_param(force_addr, ushort, 0);
 127MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller");
 128
 129static struct pci_driver sis5595_driver;
 130static unsigned short sis5595_base;
 131static struct pci_dev *sis5595_pdev;
 132
 133static u8 sis5595_read(u8 reg)
 134{
 135        outb(reg, sis5595_base + SMB_INDEX);
 136        return inb(sis5595_base + SMB_DAT);
 137}
 138
 139static void sis5595_write(u8 reg, u8 data)
 140{
 141        outb(reg, sis5595_base + SMB_INDEX);
 142        outb(data, sis5595_base + SMB_DAT);
 143}
 144
 145static int sis5595_setup(struct pci_dev *SIS5595_dev)
 146{
 147        u16 a;
 148        u8 val;
 149        int *i;
 150        int retval;
 151
 152        /* Look for imposters */
 153        for (i = blacklist; *i != 0; i++) {
 154                struct pci_dev *dev;
 155                dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
 156                if (dev) {
 157                        dev_err(&SIS5595_dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
 158                        pci_dev_put(dev);
 159                        return -ENODEV;
 160                }
 161        }
 162
 163        /* Determine the address of the SMBus areas */
 164        pci_read_config_word(SIS5595_dev, ACPI_BASE, &sis5595_base);
 165        if (sis5595_base == 0 && force_addr == 0) {
 166                dev_err(&SIS5595_dev->dev, "ACPI base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
 167                return -ENODEV;
 168        }
 169
 170        if (force_addr)
 171                sis5595_base = force_addr & ~(SIS5595_EXTENT - 1);
 172        dev_dbg(&SIS5595_dev->dev, "ACPI Base address: %04x\n", sis5595_base);
 173
 174        /* NB: We grab just the two SMBus registers here, but this may still
 175         * interfere with ACPI :-(  */
 176        retval = acpi_check_region(sis5595_base + SMB_INDEX, 2,
 177                                   sis5595_driver.name);
 178        if (retval)
 179                return retval;
 180
 181        if (!request_region(sis5595_base + SMB_INDEX, 2,
 182                            sis5595_driver.name)) {
 183                dev_err(&SIS5595_dev->dev, "SMBus registers 0x%04x-0x%04x already in use!\n",
 184                        sis5595_base + SMB_INDEX, sis5595_base + SMB_INDEX + 1);
 185                return -ENODEV;
 186        }
 187
 188        if (force_addr) {
 189                dev_info(&SIS5595_dev->dev, "forcing ISA address 0x%04X\n", sis5595_base);
 190                if (pci_write_config_word(SIS5595_dev, ACPI_BASE, sis5595_base)
 191                    != PCIBIOS_SUCCESSFUL)
 192                        goto error;
 193                if (pci_read_config_word(SIS5595_dev, ACPI_BASE, &a)
 194                    != PCIBIOS_SUCCESSFUL)
 195                        goto error;
 196                if ((a & ~(SIS5595_EXTENT - 1)) != sis5595_base) {
 197                        /* doesn't work for some chips! */
 198                        dev_err(&SIS5595_dev->dev, "force address failed - not supported?\n");
 199                        goto error;
 200                }
 201        }
 202
 203        if (pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val)
 204            != PCIBIOS_SUCCESSFUL)
 205                goto error;
 206        if ((val & 0x80) == 0) {
 207                dev_info(&SIS5595_dev->dev, "enabling ACPI\n");
 208                if (pci_write_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, val | 0x80)
 209                    != PCIBIOS_SUCCESSFUL)
 210                        goto error;
 211                if (pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val)
 212                    != PCIBIOS_SUCCESSFUL)
 213                        goto error;
 214                if ((val & 0x80) == 0) {
 215                        /* doesn't work for some chips? */
 216                        dev_err(&SIS5595_dev->dev, "ACPI enable failed - not supported?\n");
 217                        goto error;
 218                }
 219        }
 220
 221        /* Everything is happy */
 222        return 0;
 223
 224error:
 225        release_region(sis5595_base + SMB_INDEX, 2);
 226        return -ENODEV;
 227}
 228
 229static int sis5595_transaction(struct i2c_adapter *adap)
 230{
 231        int temp;
 232        int result = 0;
 233        int timeout = 0;
 234
 235        /* Make sure the SMBus host is ready to start transmitting */
 236        temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
 237        if (temp != 0x00) {
 238                dev_dbg(&adap->dev, "SMBus busy (%04x). Resetting...\n", temp);
 239                sis5595_write(SMB_STS_LO, temp & 0xff);
 240                sis5595_write(SMB_STS_HI, temp >> 8);
 241                if ((temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8)) != 0x00) {
 242                        dev_dbg(&adap->dev, "Failed! (%02x)\n", temp);
 243                        return -EBUSY;
 244                } else {
 245                        dev_dbg(&adap->dev, "Successful!\n");
 246                }
 247        }
 248
 249        /* start the transaction by setting bit 4 */
 250        sis5595_write(SMB_CTL_LO, sis5595_read(SMB_CTL_LO) | 0x10);
 251
 252        /* We will always wait for a fraction of a second! */
 253        do {
 254                msleep(1);
 255                temp = sis5595_read(SMB_STS_LO);
 256        } while (!(temp & 0x40) && (timeout++ < MAX_TIMEOUT));
 257
 258        /* If the SMBus is still busy, we give up */
 259        if (timeout > MAX_TIMEOUT) {
 260                dev_dbg(&adap->dev, "SMBus Timeout!\n");
 261                result = -ETIMEDOUT;
 262        }
 263
 264        if (temp & 0x10) {
 265                dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
 266                result = -ENXIO;
 267        }
 268
 269        if (temp & 0x20) {
 270                dev_err(&adap->dev, "Bus collision! SMBus may be locked until "
 271                        "next hard reset (or not...)\n");
 272                /* Clock stops and slave is stuck in mid-transmission */
 273                result = -EIO;
 274        }
 275
 276        temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
 277        if (temp != 0x00) {
 278                sis5595_write(SMB_STS_LO, temp & 0xff);
 279                sis5595_write(SMB_STS_HI, temp >> 8);
 280        }
 281
 282        temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
 283        if (temp != 0x00)
 284                dev_dbg(&adap->dev, "Failed reset at end of transaction (%02x)\n", temp);
 285
 286        return result;
 287}
 288
 289/* Return negative errno on error. */
 290static s32 sis5595_access(struct i2c_adapter *adap, u16 addr,
 291                          unsigned short flags, char read_write,
 292                          u8 command, int size, union i2c_smbus_data *data)
 293{
 294        int status;
 295
 296        switch (size) {
 297        case I2C_SMBUS_QUICK:
 298                sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
 299                size = SIS5595_QUICK;
 300                break;
 301        case I2C_SMBUS_BYTE:
 302                sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
 303                if (read_write == I2C_SMBUS_WRITE)
 304                        sis5595_write(SMB_CMD, command);
 305                size = SIS5595_BYTE;
 306                break;
 307        case I2C_SMBUS_BYTE_DATA:
 308                sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
 309                sis5595_write(SMB_CMD, command);
 310                if (read_write == I2C_SMBUS_WRITE)
 311                        sis5595_write(SMB_BYTE, data->byte);
 312                size = SIS5595_BYTE_DATA;
 313                break;
 314        case I2C_SMBUS_PROC_CALL:
 315        case I2C_SMBUS_WORD_DATA:
 316                sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
 317                sis5595_write(SMB_CMD, command);
 318                if (read_write == I2C_SMBUS_WRITE) {
 319                        sis5595_write(SMB_BYTE, data->word & 0xff);
 320                        sis5595_write(SMB_BYTE + 1,
 321                                      (data->word & 0xff00) >> 8);
 322                }
 323                size = (size == I2C_SMBUS_PROC_CALL) ? SIS5595_PROC_CALL : SIS5595_WORD_DATA;
 324                break;
 325        default:
 326                dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
 327                return -EOPNOTSUPP;
 328        }
 329
 330        sis5595_write(SMB_CTL_LO, ((size & 0x0E)));
 331
 332        status = sis5595_transaction(adap);
 333        if (status)
 334                return status;
 335
 336        if ((size != SIS5595_PROC_CALL) &&
 337            ((read_write == I2C_SMBUS_WRITE) || (size == SIS5595_QUICK)))
 338                return 0;
 339
 340
 341        switch (size) {
 342        case SIS5595_BYTE:
 343        case SIS5595_BYTE_DATA:
 344                data->byte = sis5595_read(SMB_BYTE);
 345                break;
 346        case SIS5595_WORD_DATA:
 347        case SIS5595_PROC_CALL:
 348                data->word = sis5595_read(SMB_BYTE) + (sis5595_read(SMB_BYTE + 1) << 8);
 349                break;
 350        }
 351        return 0;
 352}
 353
 354static u32 sis5595_func(struct i2c_adapter *adapter)
 355{
 356        return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
 357            I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
 358            I2C_FUNC_SMBUS_PROC_CALL;
 359}
 360
 361static const struct i2c_algorithm smbus_algorithm = {
 362        .smbus_xfer     = sis5595_access,
 363        .functionality  = sis5595_func,
 364};
 365
 366static struct i2c_adapter sis5595_adapter = {
 367        .owner          = THIS_MODULE,
 368        .class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
 369        .algo           = &smbus_algorithm,
 370};
 371
 372static DEFINE_PCI_DEVICE_TABLE(sis5595_ids) = {
 373        { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, 
 374        { 0, }
 375};
 376
 377MODULE_DEVICE_TABLE (pci, sis5595_ids);
 378
 379static int sis5595_probe(struct pci_dev *dev, const struct pci_device_id *id)
 380{
 381        int err;
 382
 383        if (sis5595_setup(dev)) {
 384                dev_err(&dev->dev, "SIS5595 not detected, module not inserted.\n");
 385                return -ENODEV;
 386        }
 387
 388        /* set up the sysfs linkage to our parent device */
 389        sis5595_adapter.dev.parent = &dev->dev;
 390
 391        snprintf(sis5595_adapter.name, sizeof(sis5595_adapter.name),
 392                 "SMBus SIS5595 adapter at %04x", sis5595_base + SMB_INDEX);
 393        err = i2c_add_adapter(&sis5595_adapter);
 394        if (err) {
 395                release_region(sis5595_base + SMB_INDEX, 2);
 396                return err;
 397        }
 398
 399        /* Always return failure here.  This is to allow other drivers to bind
 400         * to this pci device.  We don't really want to have control over the
 401         * pci device, we only wanted to read as few register values from it.
 402         */
 403        sis5595_pdev =  pci_dev_get(dev);
 404        return -ENODEV;
 405}
 406
 407static struct pci_driver sis5595_driver = {
 408        .name           = "sis5595_smbus",
 409        .id_table       = sis5595_ids,
 410        .probe          = sis5595_probe,
 411};
 412
 413static int __init i2c_sis5595_init(void)
 414{
 415        return pci_register_driver(&sis5595_driver);
 416}
 417
 418static void __exit i2c_sis5595_exit(void)
 419{
 420        pci_unregister_driver(&sis5595_driver);
 421        if (sis5595_pdev) {
 422                i2c_del_adapter(&sis5595_adapter);
 423                release_region(sis5595_base + SMB_INDEX, 2);
 424                pci_dev_put(sis5595_pdev);
 425                sis5595_pdev = NULL;
 426        }
 427}
 428
 429MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
 430MODULE_DESCRIPTION("SIS5595 SMBus driver");
 431MODULE_LICENSE("GPL");
 432
 433module_init(i2c_sis5595_init);
 434module_exit(i2c_sis5595_exit);
 435
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.