linux/drivers/i2c/busses/i2c-amd756.c
<<
>>
Prefs
   1/*
   2    Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.org>
   3
   4    Shamelessly ripped from i2c-piix4.c:
   5
   6    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> and
   7    Philip Edelbrock <phil@netroedge.com>
   8
   9    This program is free software; you can redistribute it and/or modify
  10    it under the terms of the GNU General Public License as published by
  11    the Free Software Foundation; either version 2 of the License, or
  12    (at your option) any later version.
  13
  14    This program is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18*/
  19
  20/*
  21    2002-04-08: Added nForce support. (Csaba Halasz)
  22    2002-10-03: Fixed nForce PnP I/O port. (Michael Steil)
  23    2002-12-28: Rewritten into something that resembles a Linux driver (hch)
  24    2003-11-29: Added back AMD8111 removed by the previous rewrite.
  25                (Philip Pokorny)
  26*/
  27
  28/*
  29   Supports AMD756, AMD766, AMD768, AMD8111 and nVidia nForce
  30   Note: we assume there can only be one device, with one SMBus interface.
  31*/
  32
  33#include <linux/module.h>
  34#include <linux/pci.h>
  35#include <linux/kernel.h>
  36#include <linux/delay.h>
  37#include <linux/stddef.h>
  38#include <linux/ioport.h>
  39#include <linux/i2c.h>
  40#include <linux/acpi.h>
  41#include <linux/io.h>
  42
  43/* AMD756 SMBus address offsets */
  44#define SMB_ADDR_OFFSET         0xE0
  45#define SMB_IOSIZE              16
  46#define SMB_GLOBAL_STATUS       (0x0 + amd756_ioport)
  47#define SMB_GLOBAL_ENABLE       (0x2 + amd756_ioport)
  48#define SMB_HOST_ADDRESS        (0x4 + amd756_ioport)
  49#define SMB_HOST_DATA           (0x6 + amd756_ioport)
  50#define SMB_HOST_COMMAND        (0x8 + amd756_ioport)
  51#define SMB_HOST_BLOCK_DATA     (0x9 + amd756_ioport)
  52#define SMB_HAS_DATA            (0xA + amd756_ioport)
  53#define SMB_HAS_DEVICE_ADDRESS  (0xC + amd756_ioport)
  54#define SMB_HAS_HOST_ADDRESS    (0xE + amd756_ioport)
  55#define SMB_SNOOP_ADDRESS       (0xF + amd756_ioport)
  56
  57/* PCI Address Constants */
  58
  59/* address of I/O space */
  60#define SMBBA           0x058           /* mh */
  61#define SMBBANFORCE     0x014
  62
  63/* general configuration */
  64#define SMBGCFG         0x041           /* mh */
  65
  66/* silicon revision code */
  67#define SMBREV          0x008
  68
  69/* Other settings */
  70#define MAX_TIMEOUT     500
  71
  72/* AMD756 constants */
  73#define AMD756_QUICK            0x00
  74#define AMD756_BYTE             0x01
  75#define AMD756_BYTE_DATA        0x02
  76#define AMD756_WORD_DATA        0x03
  77#define AMD756_PROCESS_CALL     0x04
  78#define AMD756_BLOCK_DATA       0x05
  79
  80static struct pci_driver amd756_driver;
  81static unsigned short amd756_ioport;
  82
  83/* 
  84  SMBUS event = I/O 28-29 bit 11
  85     see E0 for the status bits and enabled in E2
  86     
  87*/
  88#define GS_ABRT_STS     (1 << 0)
  89#define GS_COL_STS      (1 << 1)
  90#define GS_PRERR_STS    (1 << 2)
  91#define GS_HST_STS      (1 << 3)
  92#define GS_HCYC_STS     (1 << 4)
  93#define GS_TO_STS       (1 << 5)
  94#define GS_SMB_STS      (1 << 11)
  95
  96#define GS_CLEAR_STS    (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \
  97                         GS_HCYC_STS | GS_TO_STS )
  98
  99#define GE_CYC_TYPE_MASK        (7)
 100#define GE_HOST_STC             (1 << 3)
 101#define GE_ABORT                (1 << 5)
 102
 103
 104static int amd756_transaction(struct i2c_adapter *adap)
 105{
 106        int temp;
 107        int result = 0;
 108        int timeout = 0;
 109
 110        dev_dbg(&adap->dev, "Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, "
 111                "DAT=%04x\n", inw_p(SMB_GLOBAL_STATUS),
 112                inw_p(SMB_GLOBAL_ENABLE), inw_p(SMB_HOST_ADDRESS),
 113                inb_p(SMB_HOST_DATA));
 114
 115        /* Make sure the SMBus host is ready to start transmitting */
 116        if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) {
 117                dev_dbg(&adap->dev, "SMBus busy (%04x). Waiting...\n", temp);
 118                do {
 119                        msleep(1);
 120                        temp = inw_p(SMB_GLOBAL_STATUS);
 121                } while ((temp & (GS_HST_STS | GS_SMB_STS)) &&
 122                         (timeout++ < MAX_TIMEOUT));
 123                /* If the SMBus is still busy, we give up */
 124                if (timeout > MAX_TIMEOUT) {
 125                        dev_dbg(&adap->dev, "Busy wait timeout (%04x)\n", temp);
 126                        goto abort;
 127                }
 128                timeout = 0;
 129        }
 130
 131        /* start the transaction by setting the start bit */
 132        outw_p(inw(SMB_GLOBAL_ENABLE) | GE_HOST_STC, SMB_GLOBAL_ENABLE);
 133
 134        /* We will always wait for a fraction of a second! */
 135        do {
 136                msleep(1);
 137                temp = inw_p(SMB_GLOBAL_STATUS);
 138        } while ((temp & GS_HST_STS) && (timeout++ < MAX_TIMEOUT));
 139
 140        /* If the SMBus is still busy, we give up */
 141        if (timeout > MAX_TIMEOUT) {
 142                dev_dbg(&adap->dev, "Completion timeout!\n");
 143                goto abort;
 144        }
 145
 146        if (temp & GS_PRERR_STS) {
 147                result = -ENXIO;
 148                dev_dbg(&adap->dev, "SMBus Protocol error (no response)!\n");
 149        }
 150
 151        if (temp & GS_COL_STS) {
 152                result = -EIO;
 153                dev_warn(&adap->dev, "SMBus collision!\n");
 154        }
 155
 156        if (temp & GS_TO_STS) {
 157                result = -ETIMEDOUT;
 158                dev_dbg(&adap->dev, "SMBus protocol timeout!\n");
 159        }
 160
 161        if (temp & GS_HCYC_STS)
 162                dev_dbg(&adap->dev, "SMBus protocol success!\n");
 163
 164        outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
 165
 166#ifdef DEBUG
 167        if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) {
 168                dev_dbg(&adap->dev,
 169                        "Failed reset at end of transaction (%04x)\n", temp);
 170        }
 171#endif
 172
 173        dev_dbg(&adap->dev,
 174                "Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
 175                inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
 176                inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
 177
 178        return result;
 179
 180 abort:
 181        dev_warn(&adap->dev, "Sending abort\n");
 182        outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE);
 183        msleep(100);
 184        outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
 185        return -EIO;
 186}
 187
 188/* Return negative errno on error. */
 189static s32 amd756_access(struct i2c_adapter * adap, u16 addr,
 190                  unsigned short flags, char read_write,
 191                  u8 command, int size, union i2c_smbus_data * data)
 192{
 193        int i, len;
 194        int status;
 195
 196        switch (size) {
 197        case I2C_SMBUS_QUICK:
 198                outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
 199                       SMB_HOST_ADDRESS);
 200                size = AMD756_QUICK;
 201                break;
 202        case I2C_SMBUS_BYTE:
 203                outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
 204                       SMB_HOST_ADDRESS);
 205                if (read_write == I2C_SMBUS_WRITE)
 206                        outb_p(command, SMB_HOST_DATA);
 207                size = AMD756_BYTE;
 208                break;
 209        case I2C_SMBUS_BYTE_DATA:
 210                outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
 211                       SMB_HOST_ADDRESS);
 212                outb_p(command, SMB_HOST_COMMAND);
 213                if (read_write == I2C_SMBUS_WRITE)
 214                        outw_p(data->byte, SMB_HOST_DATA);
 215                size = AMD756_BYTE_DATA;
 216                break;
 217        case I2C_SMBUS_WORD_DATA:
 218                outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
 219                       SMB_HOST_ADDRESS);
 220                outb_p(command, SMB_HOST_COMMAND);
 221                if (read_write == I2C_SMBUS_WRITE)
 222                        outw_p(data->word, SMB_HOST_DATA);      /* TODO: endian???? */
 223                size = AMD756_WORD_DATA;
 224                break;
 225        case I2C_SMBUS_BLOCK_DATA:
 226                outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
 227                       SMB_HOST_ADDRESS);
 228                outb_p(command, SMB_HOST_COMMAND);
 229                if (read_write == I2C_SMBUS_WRITE) {
 230                        len = data->block[0];
 231                        if (len < 0)
 232                                len = 0;
 233                        if (len > 32)
 234                                len = 32;
 235                        outw_p(len, SMB_HOST_DATA);
 236                        /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
 237                        for (i = 1; i <= len; i++)
 238                                outb_p(data->block[i],
 239                                       SMB_HOST_BLOCK_DATA);
 240                }
 241                size = AMD756_BLOCK_DATA;
 242                break;
 243        default:
 244                dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
 245                return -EOPNOTSUPP;
 246        }
 247
 248        /* How about enabling interrupts... */
 249        outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE);
 250
 251        status = amd756_transaction(adap);
 252        if (status)
 253                return status;
 254
 255        if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK))
 256                return 0;
 257
 258
 259        switch (size) {
 260        case AMD756_BYTE:
 261                data->byte = inw_p(SMB_HOST_DATA);
 262                break;
 263        case AMD756_BYTE_DATA:
 264                data->byte = inw_p(SMB_HOST_DATA);
 265                break;
 266        case AMD756_WORD_DATA:
 267                data->word = inw_p(SMB_HOST_DATA);      /* TODO: endian???? */
 268                break;
 269        case AMD756_BLOCK_DATA:
 270                data->block[0] = inw_p(SMB_HOST_DATA) & 0x3f;
 271                if(data->block[0] > 32)
 272                        data->block[0] = 32;
 273                /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
 274                for (i = 1; i <= data->block[0]; i++)
 275                        data->block[i] = inb_p(SMB_HOST_BLOCK_DATA);
 276                break;
 277        }
 278
 279        return 0;
 280}
 281
 282static u32 amd756_func(struct i2c_adapter *adapter)
 283{
 284        return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
 285            I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
 286            I2C_FUNC_SMBUS_BLOCK_DATA;
 287}
 288
 289static const struct i2c_algorithm smbus_algorithm = {
 290        .smbus_xfer     = amd756_access,
 291        .functionality  = amd756_func,
 292};
 293
 294struct i2c_adapter amd756_smbus = {
 295        .owner          = THIS_MODULE,
 296        .class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
 297        .algo           = &smbus_algorithm,
 298};
 299
 300enum chiptype { AMD756, AMD766, AMD768, NFORCE, AMD8111 };
 301static const char* chipname[] = {
 302        "AMD756", "AMD766", "AMD768",
 303        "nVidia nForce", "AMD8111",
 304};
 305
 306static const struct pci_device_id amd756_ids[] = {
 307        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B),
 308          .driver_data = AMD756 },
 309        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413),
 310          .driver_data = AMD766 },
 311        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7443),
 312          .driver_data = AMD768 },
 313        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS),
 314          .driver_data = AMD8111 },
 315        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS),
 316          .driver_data = NFORCE },
 317        { 0, }
 318};
 319
 320MODULE_DEVICE_TABLE (pci, amd756_ids);
 321
 322static int amd756_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 323{
 324        int nforce = (id->driver_data == NFORCE);
 325        int error;
 326        u8 temp;
 327        
 328        if (amd756_ioport) {
 329                dev_err(&pdev->dev, "Only one device supported "
 330                       "(you have a strange motherboard, btw)\n");
 331                return -ENODEV;
 332        }
 333
 334        if (nforce) {
 335                if (PCI_FUNC(pdev->devfn) != 1)
 336                        return -ENODEV;
 337
 338                pci_read_config_word(pdev, SMBBANFORCE, &amd756_ioport);
 339                amd756_ioport &= 0xfffc;
 340        } else { /* amd */
 341                if (PCI_FUNC(pdev->devfn) != 3)
 342                        return -ENODEV;
 343
 344                pci_read_config_byte(pdev, SMBGCFG, &temp);
 345                if ((temp & 128) == 0) {
 346                        dev_err(&pdev->dev,
 347                                "Error: SMBus controller I/O not enabled!\n");
 348                        return -ENODEV;
 349                }
 350
 351                /* Determine the address of the SMBus areas */
 352                /* Technically it is a dword but... */
 353                pci_read_config_word(pdev, SMBBA, &amd756_ioport);
 354                amd756_ioport &= 0xff00;
 355                amd756_ioport += SMB_ADDR_OFFSET;
 356        }
 357
 358        error = acpi_check_region(amd756_ioport, SMB_IOSIZE,
 359                                  amd756_driver.name);
 360        if (error)
 361                return -ENODEV;
 362
 363        if (!request_region(amd756_ioport, SMB_IOSIZE, amd756_driver.name)) {
 364                dev_err(&pdev->dev, "SMB region 0x%x already in use!\n",
 365                        amd756_ioport);
 366                return -ENODEV;
 367        }
 368
 369        pci_read_config_byte(pdev, SMBREV, &temp);
 370        dev_dbg(&pdev->dev, "SMBREV = 0x%X\n", temp);
 371        dev_dbg(&pdev->dev, "AMD756_smba = 0x%X\n", amd756_ioport);
 372
 373        /* set up the sysfs linkage to our parent device */
 374        amd756_smbus.dev.parent = &pdev->dev;
 375
 376        snprintf(amd756_smbus.name, sizeof(amd756_smbus.name),
 377                 "SMBus %s adapter at %04x", chipname[id->driver_data],
 378                 amd756_ioport);
 379
 380        error = i2c_add_adapter(&amd756_smbus);
 381        if (error) {
 382                dev_err(&pdev->dev,
 383                        "Adapter registration failed, module not inserted\n");
 384                goto out_err;
 385        }
 386
 387        return 0;
 388
 389 out_err:
 390        release_region(amd756_ioport, SMB_IOSIZE);
 391        return error;
 392}
 393
 394static void amd756_remove(struct pci_dev *dev)
 395{
 396        i2c_del_adapter(&amd756_smbus);
 397        release_region(amd756_ioport, SMB_IOSIZE);
 398}
 399
 400static struct pci_driver amd756_driver = {
 401        .name           = "amd756_smbus",
 402        .id_table       = amd756_ids,
 403        .probe          = amd756_probe,
 404        .remove         = amd756_remove,
 405};
 406
 407module_pci_driver(amd756_driver);
 408
 409MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>");
 410MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver");
 411MODULE_LICENSE("GPL");
 412
 413EXPORT_SYMBOL(amd756_smbus);
 414